1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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
10#include <config_features.h>
11
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>
27
28#include <osl/process.h>
29#include <osl/thread.h>
30#include <rtl/bootstrap.h>
31#include <rtl/digest.h>
32#include <rtl/process.h>
33#include <rtl/ustrbuf.h>
34#include <sal/main.h>
35
36#include "args.h"
37#include "../../source/inc/exithelper.h"
38#include "splashx.h"
39
40#define PIPEDEFAULTPATH "/tmp"
41#define PIPEALTERNATEPATH "/var/tmp"
42
43/* Easier conversions: rtl_uString to rtl_String */
44static rtl_String *
45ustr_to_str( rtl_uString *pStr )
46{
47 rtl_String *pOut = NULL;
48
49 rtl_uString2String( &pOut, rtl_uString_getStr( pStr ),
50 rtl_uString_getLength( pStr ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
51
52 return pOut;
53}
54
55/* Easier conversions: char * to rtl_uString */
56static rtl_uString *
57charp_to_ustr( const char *pStr )
58{
59 rtl_uString *pOut = NULL;
60
61 rtl_string2UString( &pOut, pStr, strlen( pStr ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
62
63 return pOut;
64}
65
66/* Easier debugging of rtl_uString values. */
67#if OSL_DEBUG_LEVEL > 1
68static void
69ustr_debug( const char *pMessage, rtl_uString *pStr )
70{
71 rtl_String *pOut = ustr_to_str( pStr );
72
73 fprintf( stderr, "%s: %s\n", pMessage, rtl_string_getStr( pOut ) );
74
75 rtl_string_release( pOut );
76 return;
77}
78#else
79#define ustr_debug( a, b ) {}
80#endif
81
82typedef struct {
83 int status_fd;
84 oslProcess child;
85} ChildInfo;
86
87static int
88child_info_get_status_fd (ChildInfo *info)
89{
90 return info->status_fd;
91}
92
93static void
94child_info_destroy (ChildInfo *info)
95{
96 close (info->status_fd);
97 osl_freeProcessHandle (info->child);
98 free (info);
99}
100
101static ChildInfo *
102child_spawn ( Args *args, sal_Bool bAllArgs, sal_Bool bWithStatus )
103{
104 rtl_uString *pApp = NULL, *pTmp = NULL;
105 rtl_uString **ppArgs;
106 sal_uInt32 nArgs, i;
107 char buffer[64];
108 ChildInfo *info;
109 int status_pipe[2];
110 oslProcessError nError;
111
112 info = calloc (1, sizeof (ChildInfo));
113
114 /* create pipe */
115 if ( pipe( status_pipe ) < 0 )
116 {
117 fprintf( stderr, "ERROR: no file handles\n");
118 exit( 1 );
119 }
120 info->status_fd = status_pipe[0];
121
122 /* application name */
123 rtl_uString_newFromAscii( &pApp, "file://" );
124 rtl_uString_newConcat( &pApp, pApp, args->pAppPath );
125 rtl_uString_newFromAscii( &pTmp, "soffice.bin" );
126 rtl_uString_newConcat( &pApp, pApp, pTmp );
127 rtl_uString_release( pTmp );
128 pTmp = NULL;
129
130 /* copy args */
131 nArgs = bAllArgs ? args->nArgsTotal : args->nArgsEnv;
132 ppArgs = (rtl_uString **)calloc( nArgs + 1, sizeof( rtl_uString* ) );
133 for ( i = 0; i < nArgs; ++i )
134 ppArgs[i] = args->ppArgs[i];
135
136 if( bWithStatus )
137 {
138 /* add the pipe arg */
139 snprintf (buffer, 63, "--splash-pipe=%d", status_pipe[1]);
140 rtl_uString_newFromAscii( &pTmp, buffer );
141 ppArgs[nArgs] = pTmp;
142 ++nArgs;
143 }
144
145 /* start the main process */
146 nError = osl_executeProcess( pApp, ppArgs, nArgs,
147 osl_Process_NORMAL,
148 NULL,
149 NULL,
150 NULL, 0,
151 &info->child );
152
153 if (pTmp)
154 rtl_uString_release( pTmp );
155 free (ppArgs);
156
157 if ( nError != osl_Process_E_None )
158 {
159 fprintf( stderr, "ERROR %d forking process", nError );
160 ustr_debug( "", pApp );
161 rtl_uString_release( pApp );
162 _exit (1);
163 }
164
165 rtl_uString_release( pApp );
166 close( status_pipe[1] );
167
168 return info;
169}
170
171static sal_Bool
172child_exited_wait (ChildInfo *info, sal_Bool bShortWait)
173{
174 TimeValue t = { 0, 250 /* ms */ * 1000 * 1000 };
175 if (!bShortWait)
176 t.Seconds = 1024;
177 return osl_joinProcessWithTimeout (info->child, &t) != osl_Process_E_TimedOut;
178}
179
180static int
181child_get_exit_code (ChildInfo *info)
182{
183 oslProcessInfo inf;
184
185 inf.Code = -1;
186 inf.Size = sizeof (inf);
187 if (osl_getProcessInfo (info->child, osl_Process_EXITCODE, &inf) != osl_Process_E_None)
188 {
189 fprintf (stderr, "Warning: failed to fetch libreoffice exit status\n");
190 return -1;
191 }
192 return inf.Code;
193}
194
195typedef enum { ProgressContinue, ProgressRestart, ProgressExit } ProgressStatus;
196
197/* Path of the application, with trailing slash. */
198static rtl_uString *
199get_app_path( const char *pAppExec )
200{
201 char pRealPath[PATH_MAX];
202 rtl_uString *pResult;
203 sal_Int32 len;
204 char* dummy;
205
206 char *pOrigPath = strdup( pAppExec );
207 char *pPath = dirname( pOrigPath );
208
209 dummy = realpath( pPath, pRealPath );
210 (void)dummy;
211 pResult = charp_to_ustr( pRealPath );
212 free( pOrigPath );
213
214 len = rtl_uString_getLength(pResult);
215 if (len > 0 && rtl_uString_getStr(pResult)[len - 1] != '/')
216 {
217 rtl_uString *pSlash = NULL;
218 rtl_uString_newFromAscii(&pSlash, "/");
219 rtl_uString_newConcat(&pResult, pResult, pSlash);
220 rtl_uString_release(pSlash);
221 }
222
223 return pResult;
224}
225
226/* Compute the OOo md5 hash from 'pText' */
227static rtl_uString *
228get_md5hash( rtl_uString *pText )
229{
230 rtl_uString *pResult = NULL;
231 sal_Int32 nCapacity = 100;
232 unsigned char *pData = NULL;
233 sal_uInt32 nSize = 0;
234 rtlDigest digest;
235 sal_uInt32 md5_key_len = 0;
236 sal_uInt8* md5_buf = NULL;
237 sal_uInt32 i = 0;
238#if OSL_DEBUG_LEVEL > 1
239 rtl_String *pOut;
240#endif
241
242 if ( !pText )
243 return NULL;
244
245#if OSL_DEBUG_LEVEL > 1
246 pOut = ustr_to_str( pText );
247 fprintf (stderr, "Generate pipe md5 for '%s'\n", pOut->buffer);
248 rtl_string_release( pOut );
249#endif
250
251 pData = (unsigned char *)rtl_uString_getStr( pText );
252 nSize = rtl_uString_getLength( pText ) * sizeof( sal_Unicode );
253 if ( !pData )
254 return NULL;
255
256 digest = rtl_digest_create( rtl_Digest_AlgorithmMD5 );
257 if ( digest == 0 )
258 return NULL;
259
260 md5_key_len = rtl_digest_queryLength( digest );
261 md5_buf = (sal_uInt8 *)calloc( md5_key_len, sizeof( sal_uInt8 ) );
262
263 rtl_digest_init( digest, pData , nSize );
264 rtl_digest_update( digest, pData, nSize );
265 rtl_digest_get( digest, md5_buf, md5_key_len );
266 rtl_digest_destroy( digest );
267
268 /* create hex-value string from the MD5 value to keep
269 the string size minimal */
270 rtl_uString_new_WithLength( &pResult, nCapacity );
271 for ( ; i < md5_key_len; ++i )
272 {
273 char val[3];
274 snprintf( val, 3, "%x", md5_buf[i] ); /* sic! we ignore some of the 0's */
275
276 rtl_uStringbuffer_insert_ascii( &pResult, &nCapacity, rtl_uString_getLength( pResult ),
277 val, strlen( val ) );
278 }
279
280 /* cleanup */
281 free( md5_buf );
282
283 return pResult;
284}
285
286/* Construct the pipe name */
287static rtl_uString *
288get_pipe_path( rtl_uString *pAppPath )
289{
290 rtl_uString *pPath = NULL, *pTmp = NULL, *pUserInstallation = NULL;
291 rtl_uString *pResult = NULL, *pBasePath = NULL, *pAbsUserInstallation = NULL;
292 rtlBootstrapHandle handle;
293 rtl_uString *pMd5hash = NULL;
294 sal_Unicode pUnicode[RTL_USTR_MAX_VALUEOFINT32];
295
296 /* setup bootstrap filename */
297 rtl_uString_newFromAscii( &pPath, "file://" );
298 rtl_uString_newConcat( &pPath, pPath, pAppPath );
299 rtl_uString_newConcat( &pPath, pPath, pTmp );
300 rtl_uString_newFromAscii( &pTmp, SAL_CONFIGFILE( "bootstrap" ) );
301 rtl_uString_newConcat( &pPath, pPath, pTmp );
302
303 ustr_debug( "bootstap", pPath );
304
305 /* read userinstallation value */
306 handle = rtl_bootstrap_args_open( pPath );
307
308 rtl_uString_newFromAscii( &pTmp, "UserInstallation" );
309 rtl_bootstrap_get_from_handle( handle, pTmp, &pUserInstallation, NULL );
310
311 rtl_bootstrap_args_close( handle );
312
313 /* turn it into an absolute path - unwinding symlinks etc. */
314 if ( osl_getProcessWorkingDir (&pBasePath) ||
315 osl_getAbsoluteFileURL( pBasePath, pUserInstallation, &pAbsUserInstallation ) )
316 rtl_uString_newFromString (&pAbsUserInstallation, pUserInstallation);
317
318 /* create the pipe name */
319 ustr_debug( "user installation", pAbsUserInstallation );
320 pMd5hash = get_md5hash( pAbsUserInstallation );
321 if ( !pMd5hash )
322 rtl_uString_new( &pMd5hash );
323
324 if ( access( PIPEDEFAULTPATH, R_OK|W_OK ) == 0 )
325 rtl_uString_newFromAscii( &pResult, PIPEDEFAULTPATH );
326 else
327 rtl_uString_newFromAscii( &pResult, PIPEALTERNATEPATH );
328
329 rtl_uString_newFromAscii( &pTmp, "/OSL_PIPE_" );
330 rtl_uString_newConcat( &pResult, pResult, pTmp );
331
332 rtl_ustr_valueOfInt32( pUnicode, (int)getuid(), 10 );
333 rtl_uString_newFromStr( &pTmp, pUnicode );
334 rtl_uString_newConcat( &pResult, pResult, pTmp );
335
336 rtl_uString_newFromAscii( &pTmp, "_SingleOfficeIPC_" );
337 rtl_uString_newConcat( &pResult, pResult, pTmp );
338
339 rtl_uString_newConcat( &pResult, pResult, pMd5hash );
340
341 ustr_debug( "result", pResult );
342
343 /* cleanup */
344 rtl_uString_release( pMd5hash );
345 rtl_uString_release( pPath );
346 rtl_uString_release( pTmp );
347 if ( pBasePath )
348 {
349 rtl_uString_release( pBasePath );
350 }
351 rtl_uString_release( pUserInstallation );
352 rtl_uString_release( pAbsUserInstallation );
353
354 return pResult;
355}
356
357/* Get fd of the pipe of the already running OOo. */
358static int
359connect_pipe( rtl_uString *pPipePath )
360{
361 int fd;
362 size_t len;
363 struct sockaddr_un addr;
364
365 rtl_String *pPipeStr = ustr_to_str( pPipePath );
366
367 memset( &addr, 0, sizeof( addr ) );
368
369 if ( ( fd = socket( AF_UNIX, SOCK_STREAM, 0 ) ) < 0 )
370 return fd;
371
372 fcntl( fd, F_SETFD, FD_CLOEXEC );
373
374 addr.sun_family = AF_UNIX;
375 strncpy( addr.sun_path, rtl_string_getStr( pPipeStr ), sizeof( addr.sun_path ) - 1 );
376 rtl_string_release( pPipeStr );
377
378/* cut / paste from osl's pipe.c */
379#if defined(FREEBSD)
380 len = SUN_LEN( &addr );
381#else
382 len = sizeof( addr );
383#endif
384
385 if ( connect( fd, (struct sockaddr *)&addr, len ) < 0 )
386 {
387 close(fd);
388 fd = -1;
389 }
390 return fd;
391}
392
393/* Escape: "," -> "\\,", "\0" -> "\\0", "\\" -> "\\\\" */
394static rtl_uString *
395escape_path( rtl_uString *pToEscape )
396{
397 rtl_uString *pBuffer = NULL;
398 sal_Int32 nCapacity = 1000;
399 sal_Int32 i = 0;
400 sal_Int32 nEscapeLength = rtl_uString_getLength( pToEscape );
401
402 rtl_uString_new_WithLength( &pBuffer, nCapacity );
403
404 for ( ; i < nEscapeLength; ++i )
405 {
406 sal_Unicode c = pToEscape->buffer[i];
407 switch ( c )
408 {
409 case (sal_Unicode)'\0':
410 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
411 rtl_uString_getLength( pBuffer ),
412 RTL_CONSTASCII_STRINGPARAM( "\\0" ) );
413 break;
414 case (sal_Unicode)',':
415 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
416 rtl_uString_getLength( pBuffer ),
417 RTL_CONSTASCII_STRINGPARAM( "\\," ) );
418 break;
419 case (sal_Unicode)'\\':
420 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
421 rtl_uString_getLength( pBuffer ),
422 RTL_CONSTASCII_STRINGPARAM( "\\\\" ) );
423 break;
424 default:
425 rtl_uStringbuffer_insert( &pBuffer, &nCapacity,
426 rtl_uString_getLength( pBuffer ),
427 &c, 1 );
428 }
429 }
430
431 return pBuffer;
432}
433
434/* Send args to the OOo instance (using the 'fd' file descriptor) */
435static sal_Bool
436send_args( int fd, rtl_uString *pCwdPath )
437{
438 rtl_uString *pBuffer = NULL, *pTmp = NULL;
439 sal_Int32 nCapacity = 1000;
440 rtl_String *pOut = NULL;
441 sal_Bool bResult;
442 size_t nLen;
443 rtl_uString *pEscapedCwdPath = escape_path( pCwdPath );
444 sal_uInt32 nArg = 0;
445 sal_uInt32 nArgCount = rtl_getAppCommandArgCount();
446
447 rtl_uString_new_WithLength( &pBuffer, nCapacity );
448 rtl_uString_new( &pTmp );
449
450 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
451 rtl_uString_getLength( pBuffer ),
452 RTL_CONSTASCII_STRINGPARAM( "InternalIPC::Arguments" ) );
453
454 if ( rtl_uString_getLength( pEscapedCwdPath ) )
455 {
456 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
457 rtl_uString_getLength( pBuffer ),
458 RTL_CONSTASCII_STRINGPARAM( "1" ) );
459 rtl_uStringbuffer_insert( &pBuffer, &nCapacity,
460 rtl_uString_getLength( pBuffer ),
461 rtl_uString_getStr( pEscapedCwdPath ),
462 rtl_uString_getLength( pEscapedCwdPath ) );
463 }
464 else
465 {
466 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
467 rtl_uString_getLength( pBuffer ),
468 RTL_CONSTASCII_STRINGPARAM( "0" ) );
469 }
470
471 for ( nArg = 0; nArg < nArgCount; ++nArg )
472 {
473 rtl_uString *pEscapedTmp = NULL;
474 rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
475 rtl_uString_getLength( pBuffer ),
476 ",", 1 );
477
478 rtl_getAppCommandArg( nArg, &pTmp );
479
480 pEscapedTmp = escape_path( pTmp );
481
482 rtl_uStringbuffer_insert( &pBuffer, &nCapacity,
483 rtl_uString_getLength( pBuffer ),
484 rtl_uString_getStr( pEscapedTmp ),
485 rtl_uString_getLength( pEscapedTmp ) );
486
487 rtl_uString_release( pEscapedTmp );
488 }
489
490 ustr_debug( "Pass args", pBuffer );
491
492 if ( !rtl_convertUStringToString(
493 &pOut, rtl_uString_getStr( pBuffer ),
494 rtl_uString_getLength( pBuffer ), RTL_TEXTENCODING_UTF8,
495 ( RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
496 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR ) ) )
497 {
498 fprintf( stderr, "ERROR: cannot convert arguments to UTF-8" );
499 exit( 1 );
500 }
501
502 nLen = rtl_string_getLength( pOut ) + 1;
503 bResult = ( write( fd, rtl_string_getStr( pOut ), nLen ) == (ssize_t) nLen );
504
505 if ( bResult )
506 {
507 char resp[ strlen( "InternalIPC::ProcessingDone" ) ];
508 ssize_t n = read( fd, resp, SAL_N_ELEMENTS( resp ) );
509 bResult = n == (ssize_t) SAL_N_ELEMENTS( resp )
510 && (memcmp(
511 resp, "InternalIPC::ProcessingDone",
512 SAL_N_ELEMENTS( resp ) )
513 == 0);
514 }
515
516 /* cleanup */
517 rtl_uString_release( pEscapedCwdPath );
518 rtl_uString_release( pBuffer );
519 rtl_uString_release( pTmp );
520 rtl_string_release( pOut );
521
522 return bResult;
523}
524
525
526#define BUFFER_LEN 255
527
528/* Read the percent to show in splash. */
529static ProgressStatus
530read_percent( ChildInfo *info, int *pPercent )
531{
532 static char pBuffer[BUFFER_LEN + 1];
533 static char *pNext = pBuffer;
534 static ssize_t nRead = 0;
535
536 char *pBegin;
537 char *pIter;
538 char c;
539
540 /* from the last call */
541 int nNotProcessed = nRead - ( pNext - pBuffer );
542 if ( nNotProcessed >= BUFFER_LEN )
543 return sal_False;
544
545 memmove( pBuffer, pNext, nNotProcessed );
546
547 /* read data */
548 nRead = read( child_info_get_status_fd (info),
549 pBuffer + nNotProcessed, BUFFER_LEN - nNotProcessed );
550 if ( nRead < 0 ) {
551 if (errno == EINTR)
552 return ProgressContinue;
553 return ProgressExit;
554 }
555
556 nRead += nNotProcessed;
557 pBuffer[nRead] = '\0';
558
559 /* skip old data */
560 pBegin = pBuffer;
561 pNext = pBuffer;
562 for ( pIter = pBuffer; *pIter; ++pIter )
563 {
564 if ( *pIter == '\n' )
565 {
566 pBegin = pNext;
567 pNext = pIter + 1;
568 }
569 }
570
571#if OSL_DEBUG_LEVEL > 1
572 fprintf( stderr, "Got status: %s\n", pBegin );
573#endif
574 if ( !strncasecmp( pBegin, "end", 3 ) )
575 return ProgressExit;
576 else if ( !strncasecmp( pBegin, "restart", 7 ) )
577 return ProgressRestart;
578 else if ( sscanf( pBegin, "%d%c", pPercent, &c ) == 2 && c == '%' )
579 return ProgressContinue;
580
581 /* unexpected - let's exit the splash to be safe */
582 return ProgressExit;
583}
584
585/* Simple system check. */
586static void
587system_checks( void )
588{
589#ifdef LINUX
590 struct stat buf;
591
592 /* check proc is mounted - lots of things fail otherwise */
593 if ( stat( "/proc/version", &buf ) != 0 )
594 {
595 fprintf( stderr, "ERROR: /proc not mounted - LibreOffice is unlikely to work well if at all" );
596 exit( 1 );
597 }
598#endif
599}
600
601/* re-use the pagein code */
602extern int pagein_execute (int argc, char **argv);
603
604static char *build_pagein_path (Args *args, const char *pagein_name)
605{
606 char *path;
607 rtl_String *app_path;
608
609 app_path = ustr_to_str (args->pAppPath);
610 path = malloc (
611 RTL_CONSTASCII_LENGTH("@") + app_path->length + strlen (pagein_name) +
612 1);
613 strcpy (path, "@");
614 strcpy (path + 1, rtl_string_getStr (app_path));
615 strcat (path, pagein_name);
616
617 rtl_string_release( app_path );
618
619 return path;
620}
621
622void
623exec_pagein (Args *args)
624{
625 char *argv[3];
626
627 /* don't use -L - since that does a chdir that breaks relative paths */
628 argv[0] = "dummy-pagein";
629 argv[1] = build_pagein_path (args, "pagein-common");
630 if (args->pPageinType) {
631 argv[2] = build_pagein_path (args, args->pPageinType);
632 } else
633 argv[2] = NULL;
634
635 pagein_execute (args->pPageinType ? 3 : 2, argv);
636
637 if (argv[2])
638 free (argv[2]);
639 free (argv[1]);
640}
641
642#if HAVE_FEATURE_JAVA
643
644static void extend_library_path (const char *new_element)
645{
646 rtl_uString *pEnvName=NULL, *pOrigEnvVar=NULL, *pNewEnvVar=NULL;
647 const char *pathname;
648#ifdef AIX
649 pathname = "LIBPATH";
650#else
651 pathname = "LD_LIBRARY_PATH";
652#endif
653
654 rtl_uString_newFromAscii( &pEnvName, pathname );
655 rtl_uString_newFromAscii( &pNewEnvVar, new_element );
656
657 osl_getEnvironment( pEnvName, &pOrigEnvVar );
658 if (pOrigEnvVar && pOrigEnvVar->length)
659 {
660 rtl_uString *pDelim = NULL;
661 rtl_uString_newFromAscii( &pDelim, ":" );
662 rtl_uString_newConcat( &pNewEnvVar, pNewEnvVar, pDelim );
663 rtl_uString_newConcat( &pNewEnvVar, pNewEnvVar, pOrigEnvVar );
664 rtl_uString_release( pDelim );
665 }
666
667 osl_setEnvironment( pEnvName, pNewEnvVar );
668
669 if (pOrigEnvVar)
670 rtl_uString_release( pOrigEnvVar );
671 rtl_uString_release( pNewEnvVar );
672 rtl_uString_release( pEnvName );
673}
674
675static void
676exec_javaldx (Args *args)
677{
678 char newpath[4096];
679 sal_uInt32 nArgs;
680 rtl_uString *pApp;
681 rtl_uString **ppArgs;
682 rtl_uString *pTmp, *pTmp2;
683
684 oslProcess javaldx = NULL;
685 oslFileHandle fileOut= 0;
686 oslProcessError err;
687
688 ppArgs = (rtl_uString **)calloc( args->nArgsEnv + 2, sizeof( rtl_uString* ) );
689
690 for ( nArgs = 0; nArgs < args->nArgsEnv; ++nArgs )
691 ppArgs[nArgs] = args->ppArgs[nArgs];
692
693 /* Use absolute path to redirectrc */
694 pTmp = NULL;
695 rtl_uString_newFromAscii( &pTmp, "-env:INIFILENAME=vnd.sun.star.pathname:" );
696 rtl_uString_newConcat( &pTmp, pTmp, args->pAppPath );
697 pTmp2 = NULL;
698 rtl_uString_newFromAscii( &pTmp2, "redirectrc" );
699 rtl_uString_newConcat( &pTmp, pTmp, pTmp2 );
700 ppArgs[nArgs] = pTmp;
701 rtl_uString_release (pTmp2);
702 nArgs++;
703
704 /* And also to javaldx */
705 pApp = NULL;
706 rtl_uString_newFromAscii( &pApp, "file://" );
707 rtl_uString_newConcat( &pApp, pApp, args->pAppPath );
708 pTmp = NULL;
709 rtl_uString_newFromAscii( &pTmp, "../ure-link/bin/javaldx" );
710 rtl_uString_newConcat( &pApp, pApp, pTmp );
711 rtl_uString_release( pTmp );
712
713 err = osl_executeProcess_WithRedirectedIO( pApp, ppArgs, nArgs,
714 osl_Process_NORMAL,
715 NULL, // security
716 NULL, // work dir
717 NULL, 0,
718 &javaldx, // process handle
719 NULL,
720 &fileOut,
721 NULL);
722
723 rtl_uString_release( ppArgs[nArgs-1] );
724 rtl_uString_release( pApp );
725 free( ppArgs );
726
727 if( err != osl_Process_E_None)
728 {
729 fprintf (stderr, "Warning: failed to launch javaldx - java may not function correctly\n");
730 if (javaldx)
731 osl_freeProcessHandle(javaldx);
732 if (fileOut)
733 osl_closeFile(fileOut);
734 return;
735 } else {
736 char *chomp;
737 sal_uInt64 bytes_read;
738
739 /* Magically osl_readLine doesn't work with pipes with E_SPIPE - so be this lame instead: */
740 while (osl_readFile (fileOut, newpath, SAL_N_ELEMENTS (newpath), &bytes_read) == osl_File_E_INTR);
741
742 if (bytes_read <= 0) {
743 fprintf (stderr, "Warning: failed to read path from javaldx\n");
744 if (javaldx)
745 osl_freeProcessHandle(javaldx);
746 if (fileOut)
747 osl_closeFile(fileOut);
748 return;
749 }
750 newpath[bytes_read] = '\0';
751
752 if ((chomp = strstr (newpath, "\n")))
753 *chomp = '\0';
754 }
755
756#if OSL_DEBUG_LEVEL > 1
757 fprintf (stderr, "Adding javaldx path of '%s'\n", newpath);
758#endif
759 extend_library_path (newpath);
760
761 if (javaldx)
762 osl_freeProcessHandle(javaldx);
763 if (fileOut)
764 osl_closeFile(fileOut);
765}
766
767#endif
768
769// has to be a global :(
770oslProcess * volatile g_pProcess = 0;
771
772void sigterm_handler(int ignored)
773{
774 (void) ignored;
775 if (g_pProcess)
776 {
777 // forward signal to soffice.bin
778 osl_terminateProcess(g_pProcess);
779 }
780 _exit(255);
781}
782
783
784SAL_IMPLEMENT_MAIN_WITH_ARGS( argc, argv )
785{
786 int fd = 0;
787 sal_Bool bSentArgs = sal_False;
788 const char* pUsePlugin;
789 rtl_uString *pPipePath = NULL;
790 Args *args;
791 int status = 0;
792 struct splash* splash = NULL;
793 struct sigaction sigpipe_action;
794 struct sigaction sigterm_action;
795
796 /* turn SIGPIPE into an error */
797 memset(&sigpipe_action, 0, sizeof(struct sigaction));
798 sigpipe_action.sa_handler = SIG_IGN;
799 sigemptyset(&sigpipe_action.sa_mask);
800 sigaction(SIGPIPE, &sigpipe_action, 0);
801 memset(&sigterm_action, 0, sizeof(struct sigaction));
802 sigterm_action.sa_handler = &sigterm_handler;
803 sigemptyset(&sigterm_action.sa_mask);
804 sigaction(SIGTERM, &sigterm_action, 0);
805
806 args = args_parse ();
807 args->pAppPath = get_app_path( argv[0] );
808 if ( !args->pAppPath )
809 {
810 fprintf( stderr, "ERROR: Can't read app link\n" );
811 exit( 1 );
812 }
813 ustr_debug( "App path", args->pAppPath );
814
815#ifndef ENABLE_QUICKSTART_LIBPNG
816 /* we can't load and render it anyway */
817 args->bInhibitSplash = sal_True;
818#endif
819
820 pUsePlugin = getenv( "SAL_USE_VCLPLUGIN" );
821 if ( pUsePlugin && !strcmp(pUsePlugin, "svp") )
822 args->bInhibitSplash = sal_True;
823
824 if ( !args->bInhibitPipe )
825 {
826 pPipePath = get_pipe_path( args->pAppPath );
827
828 if ( ( fd = connect_pipe( pPipePath ) ) >= 0 )
829 {
830 // Wait for answer
831 char resp[ strlen( "InternalIPC::SendArguments" ) + 1];
832 ssize_t n = read( fd, resp, SAL_N_ELEMENTS( resp ) );
833 if (n == (ssize_t) SAL_N_ELEMENTS( resp )
834 && (memcmp(
835 resp, "InternalIPC::SendArguments",
836 SAL_N_ELEMENTS( resp ) - 1) == 0)) {
837 rtl_uString *pCwdPath = NULL;
838 osl_getProcessWorkingDir( &pCwdPath );
839
840 // Then send args
841 bSentArgs = send_args( fd, pCwdPath );
842 }
843
844 close( fd );
845 }
846#if OSL_DEBUG_LEVEL > 1
847 else
848 ustr_debug( "Failed to connect to pipe", pPipePath );
849#endif
850 }
851
852 if ( !bSentArgs )
853 {
854 /* we have to prepare for, and exec the binary */
855 int nPercent = 0;
856 ChildInfo *info;
857 sal_Bool bAllArgs = sal_True;
858 sal_Bool bShortWait, bRestart;
859
860 /* sanity check pieces */
861 system_checks();
862
863 /* load splash image and create window */
864 if ( !args->bInhibitSplash )
865 {
866 splash = splash_create(args->pAppPath, argc, argv);
867 }
868
869 /* pagein */
870 if (!args->bInhibitPagein)
871 exec_pagein (args);
872
873 /* javaldx */
874#if HAVE_FEATURE_JAVA
875 if (!args->bInhibitJavaLdx)
876 exec_javaldx (args);
877#endif
878
879 do
880 {
881 bRestart = sal_False;
882
883 /* fast updates if we have somewhere to update it to */
884 bShortWait = splash ? sal_True : sal_False;
885
886 /* Periodically update the splash & the percent according
887 to what status_fd says, poll quickly only while starting */
888 info = child_spawn (args, bAllArgs, bShortWait);
889 g_pProcess = info->child;
890 while (!child_exited_wait (info, bShortWait))
891 {
892 ProgressStatus eResult;
893
894 splash_draw_progress( splash, nPercent );
895 eResult = read_percent( info, &nPercent );
896 if (eResult != ProgressContinue)
897 {
898 splash_destroy(splash);
899 splash = NULL;
900 bShortWait = sal_False;
901 }
902
903#if OSL_DEBUG_LEVEL > 1
904 fprintf( stderr, "Polling, result is %s\n",
905 ( eResult == ProgressContinue )? "continue" :
906 ( ( eResult == ProgressRestart )? "restart" : "exit" ) );
907#endif
908 }
909
910#if OSL_DEBUG_LEVEL > 1
911 fprintf (stderr, "Exited with code '%d'\n", child_get_exit_code (info));
912#endif
913
914 status = child_get_exit_code(info);
915 g_pProcess = 0; // reset
916 switch (status) {
917 case EXITHELPER_CRASH_WITH_RESTART: // re-start with just -env: parameters
918#if OSL_DEBUG_LEVEL > 1
919 fprintf (stderr, "oosplash: re-start with just -env: params !\n");
920#endif
921 bRestart = sal_True;
922 bAllArgs = sal_False;
923 break;
924 case EXITHELPER_NORMAL_RESTART: // re-start with all arguments
925#if OSL_DEBUG_LEVEL > 1
926 fprintf (stderr, "oosplash: re-start with all params !\n");
927#endif
928 bRestart = sal_True;
929 bAllArgs = sal_True;
930 break;
931 default:
932 break;
933 }
934
935 child_info_destroy (info);
936 } while (bRestart);
937 }
938
939 /* cleanup */
940 if ( pPipePath )
941 rtl_uString_release( pPipePath );
942 args_free (args);
943
944 return status;
945}
946
947/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
948