Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  start.c   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */


#include <config_java.h>

#include <signal.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <poll.h>
#include <fcntl.h>
#include <stdio.h>
#include <libgen.h>
#include <string.h>
#include <errno.h>

#include <desktop/exithelper.h>
#include <osl/process.h>
#include <osl/thread.h>
#include <rtl/bootstrap.h>
#include <rtl/digest.h>
#include <rtl/process.h>
#include <rtl/ustrbuf.h>
#include <sal/main.h>

#include "args.h"
#include "pagein.h"
#include "splashx.h"

#define PIPEDEFAULTPATH      "/tmp"
#define PIPEALTERNATEPATH    "/var/tmp"

/* Easier conversions: rtl_uString to rtl_String */
static rtl_String *ustr_to_str(rtl_uString *pStr)
{
    rtl_String *pOut = NULL;

    rtl_uString2String(&pOut, rtl_uString_getStr(pStr),
            rtl_uString_getLength(pStr), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS);

    return pOut;
}

/* Easier conversions: char * to rtl_uString */
static rtl_uString *charp_to_ustr(const char *pStr)
{
    rtl_uString *pOut = NULL;

    rtl_string2UString(&pOut, pStr, strlen(pStr), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS);

    return pOut;
}

typedef struct {
    int status_fd;
    oslProcess child;
} ChildInfo;

static int
child_info_get_status_fd(ChildInfo const *info)
{
    return info->status_fd;
}

static void
child_info_destroy(ChildInfo *info)
{
    close (info->status_fd);
    osl_freeProcessHandle (info->child);
    free (info);
}

static ChildInfo * child_spawn(Args *args, sal_Bool bAllArgs, sal_Bool bWithStatus)
{
    rtl_uString *pApp = NULL, *pTmp = NULL;
    rtl_uString **ppArgs;
    sal_uInt32 nArgs, i;
    ChildInfo *info;
    int status_pipe[2];
    oslProcessError nError;

    info = calloc (1, sizeof (ChildInfo));

    /* create pipe */
    if (pipe(status_pipe) < 0)
    {
        fprintf(stderr, "ERROR: no file handles\n");
        exit(1);
    }
    info->status_fd = status_pipe[0];

    /* application name */
    rtl_uString_newFromAscii(&pApp, "file://");
    rtl_uString_newConcat(&pApp, pApp, args->pAppPath);
    rtl_uString_newFromAscii(&pTmp, "soffice.bin");
    rtl_uString_newConcat(&pApp, pApp, pTmp);
    rtl_uString_release(pTmp);
    pTmp = NULL;

    /* copy args */
    nArgs = bAllArgs ? args->nArgsTotal : args->nArgsEnv;
    ppArgs = (rtl_uString **)calloc(nArgs + 1, sizeof(rtl_uString*));
    for (i = 0; i < nArgs; ++i)
        ppArgs[i] = args->ppArgs[i];

    if(bWithStatus)
    {
        char buffer[64];

        /* add the pipe arg */
        snprintf(buffer, 63, "--splash-pipe=%d", status_pipe[1]);
        rtl_uString_newFromAscii( &pTmp, buffer );
        ppArgs[nArgs] = pTmp;
        ++nArgs;
    }

    /* start the main process */
    nError = osl_executeProcess(pApp, ppArgs, nArgs,
                                osl_Process_NORMAL,
                                NULL,
                                NULL,
                                NULL, 0,
                                &info->child );

    if (pTmp)
        rtl_uString_release(pTmp);
    free (ppArgs);

    if (nError != osl_Process_E_None)
    {
        fprintf(stderr, "ERROR %d forking process\n", nError);
        rtl_uString_release(pApp);
        _exit (1);
    }

    rtl_uString_release(pApp);
    close( status_pipe[1] );

    return info;
}

static sal_Bool child_exited_wait(ChildInfo *info, sal_Bool bShortWait)
{
    TimeValue t = { 0, 250 /* ms */ * 1000 * 1000 };
    if (!bShortWait)
        t.Seconds = 1024;

    return osl_joinProcessWithTimeout(info->child, &t) != osl_Process_E_TimedOut;
}

static int child_get_exit_code(ChildInfo *info)
{
    oslProcessInfo inf;

    inf.Code = -1;
    inf.Size = sizeof(inf);

    if (osl_getProcessInfo(info->child, osl_Process_EXITCODE, &inf) != osl_Process_E_None)
    {
        fprintf(stderr, "Warning: failed to fetch libreoffice exit status\n");
        return -1;
    }

    return inf.Code;
}

typedef enum { ProgressContinue, ProgressRestart, ProgressExit } ProgressStatus;

/* Path of the application, with trailing slash. */
static rtl_uString *get_app_path(const char *pAppExec)
{
    char pRealPath[PATH_MAX];
    rtl_uString *pResult;
    sal_Int32 len;
    char* dummy;

    char *pOrigPath = strdup(pAppExec);
    char *pPath = dirname(pOrigPath);

    dummy = realpath(pPath, pRealPath);
    (void)dummy;
    pResult = charp_to_ustr(pRealPath);
    free(pOrigPath);

    len = rtl_uString_getLength(pResult);
    if (len > 0 && rtl_uString_getStr(pResult)[len - 1] != '/')
    {
        rtl_uString *pSlash = NULL;
        rtl_uString_newFromAscii(&pSlash, "/");
        rtl_uString_newConcat(&pResult, pResult, pSlash);
        rtl_uString_release(pSlash);
    }

    return pResult;
}

/* Compute the OOo md5 hash from 'pText' */
static rtl_uString *get_md5hash(rtl_uString *pText)
{
    rtl_uString *pResult = NULL;
    sal_Int32 nCapacity = 100;
    unsigned char *pData = NULL;
    sal_uInt32 nSize = 0;
    rtlDigest digest;
    sal_uInt32 md5_key_len = 0;
    sal_uInt8* md5_buf = NULL;
    sal_uInt32 i = 0;

    if ( !pText )
        return NULL;

    pData = (unsigned char *)rtl_uString_getStr(pText);
    nSize = rtl_uString_getLength(pText) * sizeof(sal_Unicode);
    if (!pData)
        return NULL;

    digest = rtl_digest_create(rtl_Digest_AlgorithmMD5);
    if (!digest)
        return NULL;

    md5_key_len = rtl_digest_queryLength(digest);
    md5_buf = (sal_uInt8 *)calloc(md5_key_len, sizeof(sal_uInt8));

    rtl_digest_init(digest, pData , nSize);
    rtl_digest_update(digest, pData, nSize);
    rtl_digest_get(digest, md5_buf, md5_key_len);
    rtl_digest_destroy(digest);

    /* create hex-value string from the MD5 value to keep
       the string size minimal */

    rtl_uString_new_WithLength(&pResult, nCapacity);
    for (; i < md5_key_len; ++i)
    {
        char val[3];
        snprintf(val, 3, "%x", md5_buf[i]); /* sic! we ignore some of the 0's */

        rtl_uStringbuffer_insert_ascii(&pResult, &nCapacity, rtl_uString_getLength(pResult),
                val, strlen(val));
    }

    /* cleanup */
    free(md5_buf);

    return pResult;
}

/* Construct the pipe name */
static rtl_uString *get_pipe_path(rtl_uString *pAppPath)
{
    rtl_uString *pPath = NULL, *pTmp = NULL, *pUserInstallation = NULL;
    rtl_uString *pResult = NULL, *pBasePath = NULL, *pAbsUserInstallation = NULL;
    rtlBootstrapHandle handle;
    rtl_uString *pMd5hash = NULL;
    sal_Unicode pUnicode[RTL_USTR_MAX_VALUEOFINT32];

    /* setup bootstrap filename */
    rtl_uString_newFromAscii(&pPath, "file://");
    rtl_uString_newConcat(&pPath, pPath, pAppPath);
    rtl_uString_newConcat(&pPath, pPath, pTmp);
    rtl_uString_newFromAscii(&pTmp, SAL_CONFIGFILE("bootstrap"));
    rtl_uString_newConcat(&pPath, pPath, pTmp);

    /* read userinstallation value */
    handle = rtl_bootstrap_args_open(pPath);

    rtl_uString_newFromAscii(&pTmp, "UserInstallation");
    rtl_bootstrap_get_from_handle(handle, pTmp, &pUserInstallation, NULL);

    rtl_bootstrap_args_close(handle);

    /* turn it into an absolute path - unwinding symlinks etc. */
    if (osl_getProcessWorkingDir(&pBasePath) ||
        osl_getAbsoluteFileURL(pBasePath, pUserInstallation, &pAbsUserInstallation))
        rtl_uString_newFromString(&pAbsUserInstallation, pUserInstallation);

    /* create the pipe name */
    pMd5hash = get_md5hash(pAbsUserInstallation);
    if (!pMd5hash)
        rtl_uString_new(&pMd5hash);

    if (access(PIPEDEFAULTPATH, W_OK) == 0)
    {
        rtl_uString_newFromAscii(&pResult, PIPEDEFAULTPATH);
    }
    else if (access(PIPEALTERNATEPATH, W_OK) == 0)
    {
        rtl_uString_newFromAscii(&pResult, PIPEALTERNATEPATH);
    }
    else
    {
        fprintf(stderr, "ERROR: no valid pipe path found.\n");
        exit(1);
    }

    rtl_uString_newFromAscii(&pTmp, "/OSL_PIPE_");
    rtl_uString_newConcat(&pResult, pResult, pTmp);

    rtl_ustr_valueOfInt32(pUnicode, (int)getuid(), 10);
    rtl_uString_newFromStr(&pTmp, pUnicode);
    rtl_uString_newConcat(&pResult, pResult, pTmp);

    rtl_uString_newFromAscii(&pTmp, "_SingleOfficeIPC_");
    rtl_uString_newConcat(&pResult, pResult, pTmp);

    rtl_uString_newConcat(&pResult, pResult, pMd5hash);

    /* cleanup */
    rtl_uString_release(pMd5hash);
    rtl_uString_release(pPath);
    rtl_uString_release(pTmp);

    if (pBasePath)
        rtl_uString_release(pBasePath);

    rtl_uString_release(pUserInstallation);
    rtl_uString_release(pAbsUserInstallation);

    return pResult;
}

/* Get fd of the pipe of the already running OOo. */
static int connect_pipe(rtl_uString *pPipePath)
{
    int fd;
    size_t len;
    struct sockaddr_un addr;

    rtl_String *pPipeStr = ustr_to_str(pPipePath);

    memset(&addr, 0, sizeof(addr));

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
        return fd;

    (void)fcntl(fd, F_SETFD, FD_CLOEXEC);

    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, rtl_string_getStr(pPipeStr), sizeof(addr.sun_path) - 1);
    rtl_string_release(pPipeStr);

/* cut / paste from osl's pipe.c */
#if defined(FREEBSD)
    len = SUN_LEN(&addr);
#else
    len = sizeof(addr);
#endif

    if (connect(fd, (struct sockaddr *)&addr, len) < 0)
    {
        close(fd);
        fd = -1;
    }
    return fd;
}

/* Escape: "," -> "\\,", "\0" -> "\\0", "\\" -> "\\\\" */
static rtl_uString *escape_path(rtl_uString const *pToEscape)
{
    rtl_uString *pBuffer = NULL;
    sal_Int32 nCapacity = 1000;
    sal_Int32 i = 0;
    sal_Int32 nEscapeLength = rtl_uString_getLength(pToEscape);

    rtl_uString_new_WithLength(&pBuffer, nCapacity);

    for (; i < nEscapeLength; ++i)
    {
        sal_Unicode c = pToEscape->buffer[i];
        switch (c)
        {
            case '\0':
                rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
                        rtl_uString_getLength(pBuffer),
                        RTL_CONSTASCII_STRINGPARAM("\\0"));
                break;
            case ',':
                rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
                        rtl_uString_getLength(pBuffer),
                        RTL_CONSTASCII_STRINGPARAM("\\,"));
                break;
            case '\\':
                rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
                        rtl_uString_getLength(pBuffer),
                        RTL_CONSTASCII_STRINGPARAM("\\\\"));
                break;
            default:
                rtl_uStringbuffer_insert(&pBuffer, &nCapacity,
                        rtl_uString_getLength(pBuffer),
                        &c, 1);
        }
    }

    return pBuffer;
}

/* Send args to the LO instance (using the 'fd' file descriptor) */
static sal_Bool send_args(int fd, rtl_uString const *pCwdPath)
{
    rtl_uString *pBuffer = NULL, *pTmp = NULL;
    sal_Int32 nCapacity = 1000;
    rtl_String *pOut = NULL;
    sal_Bool bResult;
    size_t nLen;
    rtl_uString *pEscapedCwdPath = escape_path(pCwdPath);
    sal_uInt32 nArg = 0;
    sal_uInt32 nArgCount = rtl_getAppCommandArgCount();

    rtl_uString_new_WithLength(&pBuffer, nCapacity);
    rtl_uString_new(&pTmp);

    rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
            rtl_uString_getLength(pBuffer),
            RTL_CONSTASCII_STRINGPARAM("InternalIPC::Arguments"));

    if (rtl_uString_getLength(pEscapedCwdPath))
    {
        rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
            rtl_uString_getLength(pBuffer),
            RTL_CONSTASCII_STRINGPARAM("1"));

        rtl_uStringbuffer_insert(&pBuffer, &nCapacity,
                    rtl_uString_getLength(pBuffer),
                    rtl_uString_getStr(pEscapedCwdPath),
                    rtl_uString_getLength(pEscapedCwdPath));
    }
    else
    {
        rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
            rtl_uString_getLength(pBuffer),
            RTL_CONSTASCII_STRINGPARAM("0"));
    }

    for (nArg = 0; nArg < nArgCount; ++nArg)
    {
        rtl_uString *pEscapedTmp = NULL;
        rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
                rtl_uString_getLength(pBuffer),
                ",", 1);

        rtl_getAppCommandArg(nArg, &pTmp);

        pEscapedTmp = escape_path(pTmp);

        rtl_uStringbuffer_insert(&pBuffer, &nCapacity,
                rtl_uString_getLength(pBuffer),
                rtl_uString_getStr(pEscapedTmp),
                rtl_uString_getLength(pEscapedTmp));

        rtl_uString_release(pEscapedTmp);
    }

    if (!rtl_convertUStringToString(
             &pOut, rtl_uString_getStr(pBuffer),
             rtl_uString_getLength(pBuffer), RTL_TEXTENCODING_UTF8,
             (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
               | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
    {
        fprintf(stderr, "ERROR: cannot convert arguments to UTF-8\n");
        exit(1);
    }

    nLen = rtl_string_getLength(pOut) + 1;
    ssize_t n = write(fd, rtl_string_getStr(pOut), nLen);
    bResult = (n >= 0 && (size_t) n == nLen);

    if ( bResult )
    {
        char resp[SAL_N_ELEMENTS("InternalIPC::ProcessingDone")];
        n = read(fd, resp, SAL_N_ELEMENTS(resp));
        bResult = n == SAL_N_ELEMENTS(resp)
            && (memcmp(
                    resp, "InternalIPC::ProcessingDone",
                    SAL_N_ELEMENTS(resp))
                == 0);
    }

    /* cleanup */
    rtl_uString_release(pEscapedCwdPath);
    rtl_uString_release(pBuffer);
    rtl_uString_release(pTmp);
    rtl_string_release(pOut);

    return bResult;
}


#define BUFFER_LEN 255

/* Read the percent to show in splash. */
static ProgressStatus read_percent(ChildInfo const *info, int *pPercent)
{
    static char pBuffer[BUFFER_LEN + 1];
    static char *pNext = pBuffer;
    static ssize_t nRead = 0;

    char *pBegin;
    char *pIter;
    char c;

    /* from the last call */
    int nNotProcessed = nRead - (pNext - pBuffer);
    if (nNotProcessed >= BUFFER_LEN)
        return ProgressContinue;

    memmove(pBuffer, pNext, nNotProcessed);

    /* read data */
    // coverity[ tainted_data_return : FALSE ] version 2023.12.2
    ssize_t nThisRead = read(child_info_get_status_fd(info),
                             pBuffer + nNotProcessed, BUFFER_LEN - nNotProcessed);

    if (nThisRead < 0)
    {
        if (errno == EINTR)
            return ProgressContinue;

        return ProgressExit;
    }

    nRead = nThisRead + nNotProcessed;
    pBuffer[nRead] = '\0';

    /* skip old data */
    pBegin = pBuffer;
    pNext = pBuffer;
    for (pIter = pBuffer; *pIter; ++pIter)
    {
        if (*pIter == '\n')
        {
            pBegin = pNext;
            pNext = pIter + 1;
        }
    }

    if (!strncasecmp(pBegin, "end", 3))
        return ProgressExit;
    else if (!strncasecmp(pBegin, "restart", 7))
        return ProgressRestart;
    else if (sscanf(pBegin, "%d%c", pPercent, &c) == 2 && c == '%')
        return ProgressContinue;

    /* unexpected - let's exit the splash to be safe */
    return ProgressExit;
}

/* Simple system check. */
static void system_checks(void)
{
#ifdef LINUX
    struct stat buf;

    /* check proc is mounted - lots of things fail otherwise */
    if (stat("/proc/version", &buf) != 0)
    {
        fprintf(stderr, "ERROR: /proc not mounted - LibreOffice is unlikely to work well if at all\n");
        exit(1);
    }
#endif
}

static void exec_pagein (Args *args)
{
    rtl_String * path = ustr_to_str(args->pAppPath);
    pagein_execute(rtl_string_getStr(path), "pagein-common");

    if (args->pPageinType)
        pagein_execute(rtl_string_getStr(path), args->pPageinType);

    rtl_string_release(path);
}

#if HAVE_FEATURE_JAVA

static void extend_library_path(const char *new_element)
{
    rtl_uString *pEnvName=NULL, *pOrigEnvVar=NULL, *pNewEnvVar=NULL;

    rtl_uString_newFromAscii(&pEnvName, "LD_LIBRARY_PATH");
    rtl_uString_newFromAscii(&pNewEnvVar, new_element);

    osl_getEnvironment(pEnvName, &pOrigEnvVar);
    if (pOrigEnvVar && pOrigEnvVar->length)
    {
        rtl_uString *pDelim = NULL;
        rtl_uString_newFromAscii(&pDelim, ":");
        rtl_uString_newConcat(&pNewEnvVar, pNewEnvVar, pDelim);
        rtl_uString_newConcat(&pNewEnvVar, pNewEnvVar, pOrigEnvVar);
        rtl_uString_release(pDelim);
    }

    osl_setEnvironment(pEnvName, pNewEnvVar);

    if (pOrigEnvVar)
        rtl_uString_release(pOrigEnvVar);

    rtl_uString_release(pNewEnvVar);
    rtl_uString_release(pEnvName);
}

static void exec_javaldx(Args *args)
{
    char newpath[4096];
    sal_uInt32 nArgs;
    rtl_uString *pApp;
    rtl_uString **ppArgs;
    rtl_uString *pTmp, *pTmp2;

    oslProcess javaldx = NULL;
    oslFileHandle fileOut = NULL;
    oslProcessError err;

    ppArgs = (rtl_uString **)calloc(args->nArgsEnv + 2, sizeof(rtl_uString*));

    for (nArgs = 0; nArgs < args->nArgsEnv; ++nArgs)
        ppArgs[nArgs] = args->ppArgs[nArgs];

    /* Use absolute path to redirectrc */
    pTmp = NULL;
    rtl_uString_newFromAscii(&pTmp, "-env:INIFILENAME=vnd.sun.star.pathname:");
    rtl_uString_newConcat(&pTmp, pTmp, args->pAppPath);
    pTmp2 = NULL;
    rtl_uString_newFromAscii(&pTmp2, "redirectrc");
    rtl_uString_newConcat(&pTmp, pTmp, pTmp2);
    ppArgs[nArgs] = pTmp;
    rtl_uString_release (pTmp2);
    nArgs++;

    /* And also to javaldx */
    pApp = NULL;
    rtl_uString_newFromAscii(&pApp, "file://");
    rtl_uString_newConcat(&pApp, pApp, args->pAppPath);
    pTmp = NULL;
    rtl_uString_newFromAscii(&pTmp, "javaldx");
    rtl_uString_newConcat(&pApp, pApp, pTmp);
    rtl_uString_release(pTmp);

    err = osl_executeProcess_WithRedirectedIO(pApp, ppArgs, nArgs,
                                              osl_Process_NORMAL,
                                              NULL, // security
                                              NULL, // work dir
                                              NULL, 0,
                                              &javaldx, // process handle
                                              NULL,
                                              &fileOut,
                                              NULL);

    rtl_uString_release(ppArgs[nArgs-1]);
    rtl_uString_release(pApp);
    free(ppArgs);

    if(err != osl_Process_E_None)
    {
        putenv("javaldx_warn=failed to launch javaldx - java may not function correctly");

        if (javaldx)
            osl_freeProcessHandle(javaldx);
        if (fileOut)
            osl_closeFile(fileOut);
        return;
    }
    else
    {
        char *chomp;
        sal_uInt64 bytes_read;

        /* Magically osl_readLine doesn't work with pipes with E_SPIPE - so be this lame instead: */
        while (osl_readFile (fileOut, newpath, SAL_N_ELEMENTS (newpath), &bytes_read) == osl_File_E_INTR);

        if (bytes_read <= 0)
        {
            putenv("javaldx_warn=failed to read path from javaldx");

            if (javaldx)
                osl_freeProcessHandle(javaldx);

            if (fileOut)
                osl_closeFile(fileOut);

            return;
        }

        newpath[bytes_read] = '\0';

        if ((chomp = strstr (newpath, "\n")))
            *chomp = '\0';
    }

    if (newpath[0] != '\0') {
        extend_library_path(newpath);
    }

    if (javaldx)
        osl_freeProcessHandle(javaldx);

    if (fileOut)
        osl_closeFile(fileOut);
}

#endif

// has to be a global :(
static oslProcess * volatile g_pProcess = NULL;

static void sigterm_handler(int ignored)
{
    (void) ignored;

    if (g_pProcess) {
        int SigTermSucceded = 0;
        oslProcessInfo info;
        info.Size = sizeof(oslProcessInfo);

        // forward SIGTERM to soffice.bin and give it a chance to semi-gracefully exit
        // enough to remove named pipe
        if (osl_getProcessInfo(g_pProcess, osl_Process_IDENTIFIER, &info) == osl_Process_E_None) {
            TimeValue delay = { 1, 0 }; // 1 sec
            SigTermSucceded = kill(info.Ident, SIGTERM) == 0 &&
                              osl_joinProcessWithTimeout(g_pProcess, &delay) == osl_Process_E_None;
        }

        // didn't work, SIGKILL instead
        if (!SigTermSucceded) {
            osl_terminateProcess(g_pProcess); // uses SIGKILL to terminate soffice.bin
            osl_joinProcess(g_pProcess);
        }
    }

    _exit(255);
}


SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
{
    sal_Bool bSentArgs = sal_False;
    const char* pUsePlugin;
    rtl_uString *pPipePath = NULL;
    Args *args;
    int status = 0;
    struct splash* splash = NULL;
    struct sigaction sigpipe_action;
    struct sigaction sigterm_action;

    /* turn SIGPIPE into an error */
    memset(&sigpipe_action, 0, sizeof(struct sigaction));
    sigpipe_action.sa_handler = SIG_IGN;
    sigemptyset(&sigpipe_action.sa_mask);
    sigaction(SIGPIPE, &sigpipe_action, NULL);
    memset(&sigterm_action, 0, sizeof(struct sigaction));
    sigterm_action.sa_handler = &sigterm_handler;
    sigemptyset(&sigterm_action.sa_mask);
    sigaction(SIGTERM, &sigterm_action, NULL);

    args = args_parse();
    args->pAppPath = get_app_path(argv[0]);
    if (!args->pAppPath)
    {
        fprintf(stderr, "ERROR: Can't read app link\n");
        exit(1);
    }

#ifndef ENABLE_QUICKSTART_LIBPNG
    /* we can't load and render it anyway */
    args->bInhibitSplash = sal_True;
#endif

    pUsePlugin = getenv("SAL_USE_VCLPLUGIN");
    if (pUsePlugin && !strcmp(pUsePlugin, "svp"))
        args->bInhibitSplash = sal_True;

    if (!args->bInhibitPipe && !getenv("LIBO_FLATPAK"))
    {
        int fd = 0;
        pPipePath = get_pipe_path(args->pAppPath);

        if ((fd=connect_pipe(pPipePath)) >= 0)
        {
            // Wait for answer
            char resp[27]; // strlen("InternalIPC::SendArguments") + 1
            ssize_t n = read(fd, resp, SAL_N_ELEMENTS(resp));
            if (n == (ssize_t) SAL_N_ELEMENTS(resp) &&
                (memcmp(resp, "InternalIPC::SendArguments",
                        SAL_N_ELEMENTS(resp) - 1) == 0))
            {
                rtl_uString *pCwdPath = NULL;
                osl_getProcessWorkingDir(&pCwdPath);

                // Then send args
                bSentArgs = send_args(fd, pCwdPath);
            }

            close(fd);
        }
    }

    if (!bSentArgs)
    {
        /* we have to prepare for, and exec the binary */
        int nPercent = 0;
        ChildInfo *info;
        sal_Bool bAllArgs = sal_True;
        sal_Bool bShortWait, bRestart;

        /* sanity check pieces */
        system_checks();

        /* load splash image and create window */
        if (!args->bInhibitSplash)
            splash = splash_create(args->pAppPath, argc, argv);

        /* pagein */
        if (!args->bInhibitPagein)
            exec_pagein(args);

        /* javaldx */
#if HAVE_FEATURE_JAVA
        if (!args->bInhibitJavaLdx)
            exec_javaldx (args);
#endif

        do
        {
            bRestart = sal_False;

            /* fast updates if we have somewhere to update it to */
            bShortWait = splash ? sal_True : sal_False;

            /* Periodically update the splash & the percent according
               to what status_fd says, poll quickly only while starting */

            info = child_spawn (args, bAllArgs, bShortWait);
            g_pProcess = info->child;

            while (!child_exited_wait(info, bShortWait))
            {
                ProgressStatus eResult;

                splash_draw_progress(splash, nPercent);
                eResult = read_percent(info, &nPercent);

                if (eResult != ProgressContinue)
                {
                    splash_destroy(splash);
                    splash = NULL;
                    bShortWait = sal_False;
                }
            }

            status = child_get_exit_code(info);
            g_pProcess = NULL; // reset

            switch (status)
            {
                case EXITHELPER_CRASH_WITH_RESTART: // re-start with just -env: parameters
                    bRestart = sal_True;
                    bAllArgs = sal_False;
                    break;
                case EXITHELPER_NORMAL_RESTART: // re-start with all arguments
                    bRestart = sal_True;
                    bAllArgs = sal_True;
                    break;
                default:
                    break;
            }

            child_info_destroy(info);
        } while (bRestart);
    }

    /* cleanup */
    if (pPipePath)
        rtl_uString_release(pPipePath);

    args_free(args);

    return status;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=91 H=91 G=90

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge