LCOV - code coverage report
Current view: top level - desktop/unx/source - start.c (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 325 393 82.7 %
Date: 2015-06-13 12:38:46 Functions: 20 21 95.2 %
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 "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: */

Generated by: LCOV version 1.11