bump product version to 4.1.6.2
[LibreOffice.git] / desktop / unx / source / start.c
bloba488f955a31910625eda2ac90d5dc42aacf8d361
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 */
9 #include <signal.h>
10 #include <unistd.h>
11 #include <limits.h>
12 #include <stdlib.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <sys/socket.h>
16 #include <arpa/inet.h>
17 #include <sys/un.h>
18 #include <sys/poll.h>
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <libgen.h>
22 #include <string.h>
23 #include <errno.h>
25 #include <osl/process.h>
26 #include <osl/thread.h>
27 #include <rtl/bootstrap.h>
28 #include <rtl/digest.h>
29 #include <rtl/process.h>
30 #include <rtl/ustrbuf.h>
31 #include <sal/main.h>
33 #include "args.h"
34 #include "../../source/inc/exithelper.h"
35 #include "splashx.h"
37 #define PIPEDEFAULTPATH "/tmp"
38 #define PIPEALTERNATEPATH "/var/tmp"
40 /* Easier conversions: rtl_uString to rtl_String */
41 static rtl_String *
42 ustr_to_str( rtl_uString *pStr )
44 rtl_String *pOut = NULL;
46 rtl_uString2String( &pOut, rtl_uString_getStr( pStr ),
47 rtl_uString_getLength( pStr ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
49 return pOut;
52 /* Easier conversions: char * to rtl_uString */
53 static rtl_uString *
54 charp_to_ustr( const char *pStr )
56 rtl_uString *pOut = NULL;
58 rtl_string2UString( &pOut, pStr, strlen( pStr ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
60 return pOut;
63 /* Easier debugging of rtl_uString values. */
64 #if OSL_DEBUG_LEVEL > 1
65 static void
66 ustr_debug( const char *pMessage, rtl_uString *pStr )
68 rtl_String *pOut = ustr_to_str( pStr );
70 fprintf( stderr, "%s: %s\n", pMessage, rtl_string_getStr( pOut ) );
72 rtl_string_release( pOut );
73 return;
75 #else
76 #define ustr_debug( a, b ) {}
77 #endif
79 typedef struct {
80 int status_fd;
81 oslProcess child;
82 } ChildInfo;
84 static int
85 child_info_get_status_fd (ChildInfo *info)
87 return info->status_fd;
90 static void
91 child_info_destroy (ChildInfo *info)
93 close (info->status_fd);
94 osl_freeProcessHandle (info->child);
95 free (info);
98 static ChildInfo *
99 child_spawn ( Args *args, sal_Bool bAllArgs, sal_Bool bWithStatus )
101 rtl_uString *pApp = NULL, *pTmp = NULL;
102 rtl_uString **ppArgs;
103 sal_uInt32 nArgs, i;
104 char buffer[64];
105 ChildInfo *info;
106 int status_pipe[2];
107 oslProcessError nError;
109 info = calloc (1, sizeof (ChildInfo));
111 /* create pipe */
112 if ( pipe( status_pipe ) < 0 )
114 fprintf( stderr, "ERROR: no file handles\n");
115 exit( 1 );
117 info->status_fd = status_pipe[0];
119 /* application name */
120 rtl_uString_newFromAscii( &pApp, "file://" );
121 rtl_uString_newConcat( &pApp, pApp, args->pAppPath );
122 rtl_uString_newFromAscii( &pTmp, "soffice.bin" );
123 rtl_uString_newConcat( &pApp, pApp, pTmp );
124 rtl_uString_release( pTmp );
125 pTmp = NULL;
127 /* copy args */
128 nArgs = bAllArgs ? args->nArgsTotal : args->nArgsEnv;
129 ppArgs = (rtl_uString **)calloc( nArgs + 1, sizeof( rtl_uString* ) );
130 for ( i = 0; i < nArgs; ++i )
131 ppArgs[i] = args->ppArgs[i];
133 if( bWithStatus )
135 /* add the pipe arg */
136 snprintf (buffer, 63, "--splash-pipe=%d", status_pipe[1]);
137 rtl_uString_newFromAscii( &pTmp, buffer );
138 ppArgs[nArgs] = pTmp;
139 ++nArgs;
142 /* start the main process */
143 nError = osl_executeProcess( pApp, ppArgs, nArgs,
144 osl_Process_NORMAL,
145 NULL,
146 NULL,
147 NULL, 0,
148 &info->child );
150 if (pTmp)
151 rtl_uString_release( pTmp );
152 free (ppArgs);
154 if ( nError != osl_Process_E_None )
156 fprintf( stderr, "ERROR %d forking process", nError );
157 ustr_debug( "", pApp );
158 rtl_uString_release( pApp );
159 _exit (1);
162 rtl_uString_release( pApp );
163 close( status_pipe[1] );
165 return info;
168 static sal_Bool
169 child_exited_wait (ChildInfo *info, sal_Bool bShortWait)
171 TimeValue t = { 0, 250 /* ms */ * 1000 * 1000 };
172 if (!bShortWait)
173 t.Seconds = 1024;
174 return osl_joinProcessWithTimeout (info->child, &t) != osl_Process_E_TimedOut;
177 static int
178 child_get_exit_code (ChildInfo *info)
180 oslProcessInfo inf;
182 inf.Code = -1;
183 inf.Size = sizeof (inf);
184 if (osl_getProcessInfo (info->child, osl_Process_EXITCODE, &inf) != osl_Process_E_None)
186 fprintf (stderr, "Warning: failed to fetch libreoffice exit status\n");
187 return -1;
189 return inf.Code;
192 typedef enum { ProgressContinue, ProgressRestart, ProgressExit } ProgressStatus;
194 /* Path of the application, with trailing slash. */
195 static rtl_uString *
196 get_app_path( const char *pAppExec )
198 char pRealPath[PATH_MAX];
199 rtl_uString *pResult;
200 sal_Int32 len;
201 char* dummy;
203 char *pOrigPath = strdup( pAppExec );
204 char *pPath = dirname( pOrigPath );
206 dummy = realpath( pPath, pRealPath );
207 (void)dummy;
208 pResult = charp_to_ustr( pRealPath );
209 free( pOrigPath );
211 len = rtl_uString_getLength(pResult);
212 if (len > 0 && rtl_uString_getStr(pResult)[len - 1] != '/')
214 rtl_uString *pSlash = NULL;
215 rtl_uString_newFromAscii(&pSlash, "/");
216 rtl_uString_newConcat(&pResult, pResult, pSlash);
217 rtl_uString_release(pSlash);
220 return pResult;
223 /* Compute the OOo md5 hash from 'pText' */
224 static rtl_uString *
225 get_md5hash( rtl_uString *pText )
227 rtl_uString *pResult = NULL;
228 sal_Int32 nCapacity = 100;
229 unsigned char *pData = NULL;
230 sal_uInt32 nSize = 0;
231 rtlDigest digest;
232 sal_uInt32 md5_key_len = 0;
233 sal_uInt8* md5_buf = NULL;
234 sal_uInt32 i = 0;
235 #if OSL_DEBUG_LEVEL > 1
236 rtl_String *pOut;
237 #endif
239 if ( !pText )
240 return NULL;
242 #if OSL_DEBUG_LEVEL > 1
243 pOut = ustr_to_str( pText );
244 fprintf (stderr, "Generate pipe md5 for '%s'\n", pOut->buffer);
245 rtl_string_release( pOut );
246 #endif
248 pData = (unsigned char *)rtl_uString_getStr( pText );
249 nSize = rtl_uString_getLength( pText ) * sizeof( sal_Unicode );
250 if ( !pData )
251 return NULL;
253 digest = rtl_digest_create( rtl_Digest_AlgorithmMD5 );
254 if ( digest == 0 )
255 return NULL;
257 md5_key_len = rtl_digest_queryLength( digest );
258 md5_buf = (sal_uInt8 *)calloc( md5_key_len, sizeof( sal_uInt8 ) );
260 rtl_digest_init( digest, pData , nSize );
261 rtl_digest_update( digest, pData, nSize );
262 rtl_digest_get( digest, md5_buf, md5_key_len );
263 rtl_digest_destroy( digest );
265 /* create hex-value string from the MD5 value to keep
266 the string size minimal */
267 rtl_uString_new_WithLength( &pResult, nCapacity );
268 for ( ; i < md5_key_len; ++i )
270 char val[3];
271 snprintf( val, 3, "%x", md5_buf[i] ); /* sic! we ignore some of the 0's */
273 rtl_uStringbuffer_insert_ascii( &pResult, &nCapacity, rtl_uString_getLength( pResult ),
274 val, strlen( val ) );
277 /* cleanup */
278 free( md5_buf );
280 return pResult;
283 /* Construct the pipe name */
284 static rtl_uString *
285 get_pipe_path( rtl_uString *pAppPath )
287 rtl_uString *pPath = NULL, *pTmp = NULL, *pUserInstallation = NULL;
288 rtl_uString *pResult = NULL, *pBasePath = NULL, *pAbsUserInstallation = NULL;
289 rtlBootstrapHandle handle;
290 rtl_uString *pMd5hash = NULL;
291 sal_Unicode pUnicode[RTL_USTR_MAX_VALUEOFINT32];
293 /* setup bootstrap filename */
294 rtl_uString_newFromAscii( &pPath, "file://" );
295 rtl_uString_newConcat( &pPath, pPath, pAppPath );
296 rtl_uString_newConcat( &pPath, pPath, pTmp );
297 rtl_uString_newFromAscii( &pTmp, SAL_CONFIGFILE( "bootstrap" ) );
298 rtl_uString_newConcat( &pPath, pPath, pTmp );
300 ustr_debug( "bootstap", pPath );
302 /* read userinstallation value */
303 handle = rtl_bootstrap_args_open( pPath );
305 rtl_uString_newFromAscii( &pTmp, "UserInstallation" );
306 rtl_bootstrap_get_from_handle( handle, pTmp, &pUserInstallation, NULL );
308 rtl_bootstrap_args_close( handle );
310 /* turn it into an absolute path - unwinding symlinks etc. */
311 if ( osl_getProcessWorkingDir (&pBasePath) ||
312 osl_getAbsoluteFileURL( pBasePath, pUserInstallation, &pAbsUserInstallation ) )
313 rtl_uString_newFromString (&pAbsUserInstallation, pUserInstallation);
315 /* create the pipe name */
316 ustr_debug( "user installation", pAbsUserInstallation );
317 pMd5hash = get_md5hash( pAbsUserInstallation );
318 if ( !pMd5hash )
319 rtl_uString_new( &pMd5hash );
321 if ( access( PIPEDEFAULTPATH, R_OK|W_OK ) == 0 )
322 rtl_uString_newFromAscii( &pResult, PIPEDEFAULTPATH );
323 else
324 rtl_uString_newFromAscii( &pResult, PIPEALTERNATEPATH );
326 rtl_uString_newFromAscii( &pTmp, "/OSL_PIPE_" );
327 rtl_uString_newConcat( &pResult, pResult, pTmp );
329 rtl_ustr_valueOfInt32( pUnicode, (int)getuid(), 10 );
330 rtl_uString_newFromStr( &pTmp, pUnicode );
331 rtl_uString_newConcat( &pResult, pResult, pTmp );
333 rtl_uString_newFromAscii( &pTmp, "_SingleOfficeIPC_" );
334 rtl_uString_newConcat( &pResult, pResult, pTmp );
336 rtl_uString_newConcat( &pResult, pResult, pMd5hash );
338 ustr_debug( "result", pResult );
340 /* cleanup */
341 rtl_uString_release( pMd5hash );
342 rtl_uString_release( pPath );
343 rtl_uString_release( pTmp );
344 if ( pBasePath )
346 rtl_uString_release( pBasePath );
348 rtl_uString_release( pUserInstallation );
349 rtl_uString_release( pAbsUserInstallation );
351 return pResult;
354 /* Get fd of the pipe of the already running OOo. */
355 static int
356 connect_pipe( rtl_uString *pPipePath )
358 int fd;
359 size_t len;
360 struct sockaddr_un addr;
362 rtl_String *pPipeStr = ustr_to_str( pPipePath );
364 memset( &addr, 0, sizeof( addr ) );
366 if ( ( fd = socket( AF_UNIX, SOCK_STREAM, 0 ) ) < 0 )
367 return fd;
369 fcntl( fd, F_SETFD, FD_CLOEXEC );
371 addr.sun_family = AF_UNIX;
372 strncpy( addr.sun_path, rtl_string_getStr( pPipeStr ), sizeof( addr.sun_path ) - 1 );
373 rtl_string_release( pPipeStr );
375 /* cut / paste from osl's pipe.c */
376 #if defined(FREEBSD)
377 len = SUN_LEN( &addr );
378 #else
379 len = sizeof( addr );
380 #endif
382 if ( connect( fd, (struct sockaddr *)&addr, len ) < 0 )
384 close(fd);
385 fd = -1;
387 return fd;
390 /* Escape: "," -> "\\,", "\0" -> "\\0", "\\" -> "\\\\" */
391 static rtl_uString *
392 escape_path( rtl_uString *pToEscape )
394 rtl_uString *pBuffer = NULL;
395 sal_Int32 nCapacity = 1000;
396 sal_Int32 i = 0;
397 sal_Int32 nEscapeLength = rtl_uString_getLength( pToEscape );
399 rtl_uString_new_WithLength( &pBuffer, nCapacity );
401 for ( ; i < nEscapeLength; ++i )
403 sal_Unicode c = pToEscape->buffer[i];
404 switch ( c )
406 case (sal_Unicode)'\0':
407 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
408 rtl_uString_getLength( pBuffer ),
409 RTL_CONSTASCII_STRINGPARAM( "\\0" ) );
410 break;
411 case (sal_Unicode)',':
412 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
413 rtl_uString_getLength( pBuffer ),
414 RTL_CONSTASCII_STRINGPARAM( "\\," ) );
415 break;
416 case (sal_Unicode)'\\':
417 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
418 rtl_uString_getLength( pBuffer ),
419 RTL_CONSTASCII_STRINGPARAM( "\\\\" ) );
420 break;
421 default:
422 rtl_uStringbuffer_insert( &pBuffer, &nCapacity,
423 rtl_uString_getLength( pBuffer ),
424 &c, 1 );
428 return pBuffer;
431 /* Send args to the OOo instance (using the 'fd' file descriptor) */
432 static sal_Bool
433 send_args( int fd, rtl_uString *pCwdPath )
435 rtl_uString *pBuffer = NULL, *pTmp = NULL;
436 sal_Int32 nCapacity = 1000;
437 rtl_String *pOut = NULL;
438 sal_Bool bResult;
439 size_t nLen;
440 rtl_uString *pEscapedCwdPath = escape_path( pCwdPath );
441 sal_uInt32 nArg = 0;
442 sal_uInt32 nArgCount = rtl_getAppCommandArgCount();
444 rtl_uString_new_WithLength( &pBuffer, nCapacity );
445 rtl_uString_new( &pTmp );
447 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
448 rtl_uString_getLength( pBuffer ),
449 RTL_CONSTASCII_STRINGPARAM( "InternalIPC::Arguments" ) );
451 if ( rtl_uString_getLength( pEscapedCwdPath ) )
453 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
454 rtl_uString_getLength( pBuffer ),
455 RTL_CONSTASCII_STRINGPARAM( "1" ) );
456 rtl_uStringbuffer_insert( &pBuffer, &nCapacity,
457 rtl_uString_getLength( pBuffer ),
458 rtl_uString_getStr( pEscapedCwdPath ),
459 rtl_uString_getLength( pEscapedCwdPath ) );
461 else
463 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
464 rtl_uString_getLength( pBuffer ),
465 RTL_CONSTASCII_STRINGPARAM( "0" ) );
468 for ( nArg = 0; nArg < nArgCount; ++nArg )
470 rtl_uString *pEscapedTmp = NULL;
471 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
472 rtl_uString_getLength( pBuffer ),
473 ",", 1 );
475 rtl_getAppCommandArg( nArg, &pTmp );
477 pEscapedTmp = escape_path( pTmp );
479 rtl_uStringbuffer_insert( &pBuffer, &nCapacity,
480 rtl_uString_getLength( pBuffer ),
481 rtl_uString_getStr( pEscapedTmp ),
482 rtl_uString_getLength( pEscapedTmp ) );
484 rtl_uString_release( pEscapedTmp );
487 ustr_debug( "Pass args", pBuffer );
489 if ( !rtl_convertUStringToString(
490 &pOut, rtl_uString_getStr( pBuffer ),
491 rtl_uString_getLength( pBuffer ), RTL_TEXTENCODING_UTF8,
492 ( RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
493 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR ) ) )
495 fprintf( stderr, "ERROR: cannot convert arguments to UTF-8" );
496 exit( 1 );
499 nLen = rtl_string_getLength( pOut ) + 1;
500 bResult = ( write( fd, rtl_string_getStr( pOut ), nLen ) == (ssize_t) nLen );
502 if ( bResult )
504 char resp[ strlen( "InternalIPC::ProcessingDone" ) ];
505 ssize_t n = read( fd, resp, SAL_N_ELEMENTS( resp ) );
506 bResult = n == (ssize_t) SAL_N_ELEMENTS( resp )
507 && (memcmp(
508 resp, "InternalIPC::ProcessingDone",
509 SAL_N_ELEMENTS( resp ) )
510 == 0);
513 /* cleanup */
514 rtl_uString_release( pEscapedCwdPath );
515 rtl_uString_release( pBuffer );
516 rtl_uString_release( pTmp );
517 rtl_string_release( pOut );
519 return bResult;
523 #define BUFFER_LEN 255
525 /* Read the percent to show in splash. */
526 static ProgressStatus
527 read_percent( ChildInfo *info, int *pPercent )
529 static char pBuffer[BUFFER_LEN + 1];
530 static char *pNext = pBuffer;
531 static ssize_t nRead = 0;
533 char *pBegin;
534 char *pIter;
535 char c;
537 /* from the last call */
538 int nNotProcessed = nRead - ( pNext - pBuffer );
539 if ( nNotProcessed >= BUFFER_LEN )
540 return sal_False;
542 memmove( pBuffer, pNext, nNotProcessed );
544 /* read data */
545 nRead = read( child_info_get_status_fd (info),
546 pBuffer + nNotProcessed, BUFFER_LEN - nNotProcessed );
547 if ( nRead < 0 ) {
548 if (errno == EINTR)
549 return ProgressContinue;
550 return ProgressExit;
553 nRead += nNotProcessed;
554 pBuffer[nRead] = '\0';
556 /* skip old data */
557 pBegin = pBuffer;
558 pNext = pBuffer;
559 for ( pIter = pBuffer; *pIter; ++pIter )
561 if ( *pIter == '\n' )
563 pBegin = pNext;
564 pNext = pIter + 1;
568 #if OSL_DEBUG_LEVEL > 1
569 fprintf( stderr, "Got status: %s\n", pBegin );
570 #endif
571 if ( !strncasecmp( pBegin, "end", 3 ) )
572 return ProgressExit;
573 else if ( !strncasecmp( pBegin, "restart", 7 ) )
574 return ProgressRestart;
575 else if ( sscanf( pBegin, "%d%c", pPercent, &c ) == 2 && c == '%' )
576 return ProgressContinue;
578 /* unexpected - let's exit the splash to be safe */
579 return ProgressExit;
582 /* Simple system check. */
583 static void
584 system_checks( void )
586 #ifdef LINUX
587 struct stat buf;
589 /* check proc is mounted - lots of things fail otherwise */
590 if ( stat( "/proc/version", &buf ) != 0 )
592 fprintf( stderr, "ERROR: /proc not mounted - LibreOffice is unlikely to work well if at all" );
593 exit( 1 );
595 #endif
598 /* re-use the pagein code */
599 extern int pagein_execute (int argc, char **argv);
601 static char *build_pagein_path (Args *args, const char *pagein_name)
603 char *path;
604 rtl_String *app_path;
606 app_path = ustr_to_str (args->pAppPath);
607 path = malloc (
608 RTL_CONSTASCII_LENGTH("@") + app_path->length + strlen (pagein_name) +
610 strcpy (path, "@");
611 strcpy (path + 1, rtl_string_getStr (app_path));
612 strcat (path, pagein_name);
614 rtl_string_release( app_path );
616 return path;
619 void
620 exec_pagein (Args *args)
622 char *argv[3];
624 /* don't use -L - since that does a chdir that breaks relative paths */
625 argv[0] = "dummy-pagein";
626 argv[1] = build_pagein_path (args, "pagein-common");
627 if (args->pPageinType) {
628 argv[2] = build_pagein_path (args, args->pPageinType);
629 } else
630 argv[2] = NULL;
632 pagein_execute (args->pPageinType ? 3 : 2, argv);
634 if (argv[2])
635 free (argv[2]);
636 free (argv[1]);
639 #if defined SOLAR_JAVA
641 static void extend_library_path (const char *new_element)
643 rtl_uString *pEnvName=NULL, *pOrigEnvVar=NULL, *pNewEnvVar=NULL;
644 const char *pathname;
645 #ifdef AIX
646 pathname = "LIBPATH";
647 #else
648 pathname = "LD_LIBRARY_PATH";
649 #endif
651 rtl_uString_newFromAscii( &pEnvName, pathname );
652 rtl_uString_newFromAscii( &pNewEnvVar, new_element );
654 osl_getEnvironment( pEnvName, &pOrigEnvVar );
655 if (pOrigEnvVar && pOrigEnvVar->length)
657 rtl_uString *pDelim = NULL;
658 rtl_uString_newFromAscii( &pDelim, ":" );
659 rtl_uString_newConcat( &pNewEnvVar, pNewEnvVar, pDelim );
660 rtl_uString_newConcat( &pNewEnvVar, pNewEnvVar, pOrigEnvVar );
661 rtl_uString_release( pDelim );
664 osl_setEnvironment( pEnvName, pNewEnvVar );
666 if (pOrigEnvVar)
667 rtl_uString_release( pOrigEnvVar );
668 rtl_uString_release( pNewEnvVar );
669 rtl_uString_release( pEnvName );
672 static void
673 exec_javaldx (Args *args)
675 char newpath[4096];
676 sal_uInt32 nArgs;
677 rtl_uString *pApp;
678 rtl_uString **ppArgs;
679 rtl_uString *pTmp, *pTmp2;
681 oslProcess javaldx = NULL;
682 oslFileHandle fileOut= 0;
683 oslProcessError err;
685 ppArgs = (rtl_uString **)calloc( args->nArgsEnv + 2, sizeof( rtl_uString* ) );
687 for ( nArgs = 0; nArgs < args->nArgsEnv; ++nArgs )
688 ppArgs[nArgs] = args->ppArgs[nArgs];
690 /* Use absolute path to redirectrc */
691 pTmp = NULL;
692 rtl_uString_newFromAscii( &pTmp, "-env:INIFILENAME=vnd.sun.star.pathname:" );
693 rtl_uString_newConcat( &pTmp, pTmp, args->pAppPath );
694 pTmp2 = NULL;
695 rtl_uString_newFromAscii( &pTmp2, "redirectrc" );
696 rtl_uString_newConcat( &pTmp, pTmp, pTmp2 );
697 ppArgs[nArgs] = pTmp;
698 rtl_uString_release (pTmp2);
699 nArgs++;
701 /* And also to javaldx */
702 pApp = NULL;
703 rtl_uString_newFromAscii( &pApp, "file://" );
704 rtl_uString_newConcat( &pApp, pApp, args->pAppPath );
705 pTmp = NULL;
706 rtl_uString_newFromAscii( &pTmp, "../ure-link/bin/javaldx" );
707 rtl_uString_newConcat( &pApp, pApp, pTmp );
708 rtl_uString_release( pTmp );
710 err = osl_executeProcess_WithRedirectedIO( pApp, ppArgs, nArgs,
711 osl_Process_NORMAL,
712 NULL, // security
713 NULL, // work dir
714 NULL, 0,
715 &javaldx, // process handle
716 NULL,
717 &fileOut,
718 NULL);
720 rtl_uString_release( ppArgs[nArgs-1] );
721 rtl_uString_release( pApp );
722 free( ppArgs );
724 if( err != osl_Process_E_None)
726 fprintf (stderr, "Warning: failed to launch javaldx - java may not function correctly\n");
727 if (javaldx)
728 osl_freeProcessHandle(javaldx);
729 if (fileOut)
730 osl_closeFile(fileOut);
731 return;
732 } else {
733 char *chomp;
734 sal_uInt64 bytes_read;
736 /* Magically osl_readLine doesn't work with pipes with E_SPIPE - so be this lame instead: */
737 while (osl_readFile (fileOut, newpath, SAL_N_ELEMENTS (newpath), &bytes_read) == osl_File_E_INTR);
739 if (bytes_read <= 0) {
740 fprintf (stderr, "Warning: failed to read path from javaldx\n");
741 if (javaldx)
742 osl_freeProcessHandle(javaldx);
743 if (fileOut)
744 osl_closeFile(fileOut);
745 return;
747 newpath[bytes_read] = '\0';
749 if ((chomp = strstr (newpath, "\n")))
750 *chomp = '\0';
753 #if OSL_DEBUG_LEVEL > 1
754 fprintf (stderr, "Adding javaldx path of '%s'\n", newpath);
755 #endif
756 extend_library_path (newpath);
758 if (javaldx)
759 osl_freeProcessHandle(javaldx);
760 if (fileOut)
761 osl_closeFile(fileOut);
764 #endif
766 // has to be a global :(
767 oslProcess * volatile g_pProcess = 0;
769 void sigterm_handler(int ignored)
771 (void) ignored;
772 if (g_pProcess)
774 // forward signal to soffice.bin
775 osl_terminateProcess(g_pProcess);
777 _exit(255);
781 SAL_IMPLEMENT_MAIN_WITH_ARGS( argc, argv )
783 int fd = 0;
784 sal_Bool bSentArgs = sal_False;
785 const char* pUsePlugin;
786 rtl_uString *pPipePath = NULL;
787 Args *args;
788 int status = 0;
789 struct splash* splash = NULL;
790 struct sigaction sigpipe_action;
791 struct sigaction sigterm_action;
793 /* turn SIGPIPE into an error */
794 memset(&sigpipe_action, 0, sizeof(struct sigaction));
795 sigpipe_action.sa_handler = SIG_IGN;
796 sigemptyset(&sigpipe_action.sa_mask);
797 sigaction(SIGPIPE, &sigpipe_action, 0);
798 memset(&sigterm_action, 0, sizeof(struct sigaction));
799 sigterm_action.sa_handler = &sigterm_handler;
800 sigemptyset(&sigterm_action.sa_mask);
801 sigaction(SIGTERM, &sigterm_action, 0);
803 args = args_parse ();
804 args->pAppPath = get_app_path( argv[0] );
805 if ( !args->pAppPath )
807 fprintf( stderr, "ERROR: Can't read app link\n" );
808 exit( 1 );
810 ustr_debug( "App path", args->pAppPath );
812 #ifndef ENABLE_QUICKSTART_LIBPNG
813 /* we can't load and render it anyway */
814 args->bInhibitSplash = sal_True;
815 #endif
817 pUsePlugin = getenv( "SAL_USE_VCLPLUGIN" );
818 if ( pUsePlugin && !strcmp(pUsePlugin, "svp") )
819 args->bInhibitSplash = sal_True;
821 if ( !args->bInhibitPipe )
823 pPipePath = get_pipe_path( args->pAppPath );
825 if ( ( fd = connect_pipe( pPipePath ) ) >= 0 )
827 // Wait for answer
828 char resp[ strlen( "InternalIPC::SendArguments" ) + 1];
829 ssize_t n = read( fd, resp, SAL_N_ELEMENTS( resp ) );
830 if (n == (ssize_t) SAL_N_ELEMENTS( resp )
831 && (memcmp(
832 resp, "InternalIPC::SendArguments",
833 SAL_N_ELEMENTS( resp ) - 1) == 0)) {
834 rtl_uString *pCwdPath = NULL;
835 osl_getProcessWorkingDir( &pCwdPath );
837 // Then send args
838 bSentArgs = send_args( fd, pCwdPath );
841 close( fd );
843 #if OSL_DEBUG_LEVEL > 1
844 else
845 ustr_debug( "Failed to connect to pipe", pPipePath );
846 #endif
849 if ( !bSentArgs )
851 /* we have to prepare for, and exec the binary */
852 int nPercent = 0;
853 ChildInfo *info;
854 sal_Bool bAllArgs = sal_True;
855 sal_Bool bShortWait, bRestart;
857 /* sanity check pieces */
858 system_checks();
860 /* load splash image and create window */
861 if ( !args->bInhibitSplash )
863 splash = splash_create(args->pAppPath, argc, argv);
866 /* pagein */
867 if (!args->bInhibitPagein)
868 exec_pagein (args);
870 /* javaldx */
871 #ifdef SOLAR_JAVA
872 if (!args->bInhibitJavaLdx)
873 exec_javaldx (args);
874 #endif
878 bRestart = sal_False;
880 /* fast updates if we have somewhere to update it to */
881 bShortWait = splash ? sal_True : sal_False;
883 /* Periodically update the splash & the percent according
884 to what status_fd says, poll quickly only while starting */
885 info = child_spawn (args, bAllArgs, bShortWait);
886 g_pProcess = info->child;
887 while (!child_exited_wait (info, bShortWait))
889 ProgressStatus eResult;
891 splash_draw_progress( splash, nPercent );
892 eResult = read_percent( info, &nPercent );
893 if (eResult != ProgressContinue)
895 splash_destroy(splash);
896 splash = NULL;
897 bShortWait = sal_False;
900 #if OSL_DEBUG_LEVEL > 1
901 fprintf( stderr, "Polling, result is %s\n",
902 ( eResult == ProgressContinue )? "continue" :
903 ( ( eResult == ProgressRestart )? "restart" : "exit" ) );
904 #endif
907 #if OSL_DEBUG_LEVEL > 0
908 fprintf (stderr, "Exited with code '%d'\n", child_get_exit_code (info));
909 #endif
911 status = child_get_exit_code(info);
912 g_pProcess = 0; // reset
913 switch (status) {
914 case EXITHELPER_CRASH_WITH_RESTART: // re-start with just -env: parameters
915 #if OSL_DEBUG_LEVEL > 0
916 fprintf (stderr, "oosplash: re-start with just -env: params !\n");
917 #endif
918 bRestart = sal_True;
919 bAllArgs = sal_False;
920 break;
921 case EXITHELPER_NORMAL_RESTART: // re-start with all arguments
922 #if OSL_DEBUG_LEVEL > 0
923 fprintf (stderr, "oosplash: re-start with all params !\n");
924 #endif
925 bRestart = sal_True;
926 bAllArgs = sal_True;
927 break;
928 default:
929 break;
932 child_info_destroy (info);
933 } while (bRestart);
936 /* cleanup */
937 if ( pPipePath )
938 rtl_uString_release( pPipePath );
939 args_free (args);
941 return status;
944 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */