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

Generated by: LCOV version 1.10