LCOV - code coverage report
Current view: top level - desktop/unx/source - start.c (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 251 406 61.8 %
Date: 2014-04-14 Functions: 17 22 77.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10