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