1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_folders.h>
22 #include "deployment.hrc"
23 #include "unopkg_shared.h"
24 #include "dp_identifier.hxx"
25 #include "../../deployment/gui/dp_gui.hrc"
26 #include "lockfile.hxx"
27 #include <vcl/svapp.hxx>
28 #include <vcl/msgbox.hxx>
29 #include <rtl/bootstrap.hxx>
30 #include <rtl/strbuf.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <osl/process.h>
33 #include <osl/file.hxx>
34 #include <osl/thread.hxx>
35 #include <tools/getprocessworkingdir.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <unotools/configmgr.hxx>
38 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
39 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
40 #include <cppuhelper/bootstrap.hxx>
41 #include <comphelper/sequence.hxx>
44 using namespace ::com::sun::star
;
45 using namespace ::com::sun::star::uno
;
46 using namespace ::com::sun::star::ucb
;
50 OUString
toString( OptionInfo
const * info
)
54 buf
.appendAscii("--");
55 buf
.appendAscii(info
->m_name
);
56 if (info
->m_short_option
!= '\0')
58 buf
.appendAscii(" (short -" );
59 buf
.append(info
->m_short_option
);
62 if (info
->m_has_argument
)
63 buf
.appendAscii(" <argument>" );
64 return buf
.makeStringAndClear();
68 OptionInfo
const * getOptionInfo(
69 OptionInfo
const * list
,
70 OUString
const & opt
, sal_Unicode copt
)
72 for ( ; list
->m_name
!= 0; ++list
)
74 OptionInfo
const & option_info
= *list
;
78 option_info
.m_name
, option_info
.m_name_length
) &&
79 (copt
== '\0' || copt
== option_info
.m_short_option
))
86 OSL_ASSERT( copt
!= '\0' );
87 if (copt
== option_info
.m_short_option
)
93 OSL_FAIL( OUStringToOString(
94 opt
, osl_getThreadTextEncoding() ).getStr() );
99 bool isOption( OptionInfo
const * option_info
, sal_uInt32
* pIndex
)
101 assert(option_info
!= 0);
102 if (osl_getCommandArgCount() <= *pIndex
)
106 osl_getCommandArg( *pIndex
, &arg
.pData
);
107 sal_Int32 len
= arg
.getLength();
109 if (len
< 2 || arg
[ 0 ] != '-')
112 if (len
== 2 && arg
[ 1 ] == option_info
->m_short_option
)
115 dp_misc::TRACE(__FILE__
": identified option \'\'"
116 + OUString( option_info
->m_short_option
) + "\n");
119 if (arg
[ 1 ] == '-' && rtl_ustr_ascii_compare(
120 arg
.pData
->buffer
+ 2, option_info
->m_name
) == 0)
123 dp_misc::TRACE(__FILE__
": identified option \'"
124 + OUString::createFromAscii(option_info
->m_name
) + "\'\n");
131 bool isBootstrapVariable(sal_uInt32
* pIndex
)
133 OSL_ASSERT(osl_getCommandArgCount() >= *pIndex
);
136 osl_getCommandArg(*pIndex
, &arg
.pData
);
137 if (arg
.match("-env:"))
147 OUString
* pValue
, OptionInfo
const * option_info
, sal_uInt32
* pIndex
)
149 if (isOption( option_info
, pIndex
))
151 if (*pIndex
< osl_getCommandArgCount())
153 OSL_ASSERT( pValue
!= 0 );
154 osl_getCommandArg( *pIndex
, &pValue
->pData
);
155 dp_misc::TRACE(__FILE__
": argument value: "
167 struct ExecutableDir
: public rtl::StaticWithInit
<
168 OUString
, ExecutableDir
> {
169 const OUString
operator () () {
171 if (osl_getExecutableFile( &path
.pData
) != osl_Process_E_None
) {
172 throw RuntimeException("cannot locate executable directory!",0);
174 return path
.copy( 0, path
.lastIndexOf( '/' ) );
177 struct ProcessWorkingDir
: public rtl::StaticWithInit
<
178 OUString
, ProcessWorkingDir
> {
179 const OUString
operator () () {
181 tools::getProcessWorkingDir(workingDir
);
188 OUString
const & getExecutableDir()
190 return ExecutableDir::get();
194 OUString
const & getProcessWorkingDir()
196 return ProcessWorkingDir::get();
200 OUString
makeAbsoluteFileUrl(
201 OUString
const & sys_path
, OUString
const & base_url
, bool throw_exc
)
203 // system path to file url
205 oslFileError rc
= osl_getFileURLFromSystemPath( sys_path
.pData
, &file_url
.pData
);
206 if ( rc
!= osl_File_E_None
) {
208 if ( osl_getSystemPathFromFileURL( sys_path
.pData
, &tempPath
.pData
) == osl_File_E_None
)
214 throw RuntimeException("cannot get file url from system path: " +
220 if (osl_getAbsoluteFileURL(
221 base_url
.pData
, file_url
.pData
, &abs
.pData
) != osl_File_E_None
)
225 buf
.appendAscii( "making absolute file url failed: \"" );
226 buf
.append( base_url
);
227 buf
.appendAscii( "\" (base-url) and \"" );
228 buf
.append( file_url
);
229 buf
.appendAscii( "\" (file-url)!" );
230 throw RuntimeException( buf
.makeStringAndClear() );
234 return abs
[ abs
.getLength() -1 ] == '/'
235 ? abs
.copy( 0, abs
.getLength() -1 ) : abs
;
242 inline void printf_space( sal_Int32 space
)
245 dp_misc::writeConsole(" ");
250 OUString
const & name
, OUString
const & value
, sal_Int32 level
)
252 printf_space( level
);
253 dp_misc::writeConsole(name
+ ": " + value
+ "\n");
258 Reference
<deployment::XPackage
> const & xPackage
,
259 Reference
<XCommandEnvironment
> const & xCmdEnv
, sal_Int32 level
)
261 beans::Optional
< OUString
> id(
263 ? beans::Optional
< OUString
>(
264 true, dp_misc::getIdentifier( xPackage
) )
265 : xPackage
->getIdentifier() );
267 printf_line( "Identifier", id
.Value
, level
);
268 OUString
version(xPackage
->getVersion());
269 if (!version
.isEmpty())
270 printf_line( "Version", version
, level
+ 1 );
271 printf_line( "URL", xPackage
->getURL(), level
+ 1 );
273 beans::Optional
< beans::Ambiguous
<sal_Bool
> > option(
274 xPackage
->isRegistered( Reference
<task::XAbortChannel
>(), xCmdEnv
) );
276 if (option
.IsPresent
) {
277 beans::Ambiguous
<sal_Bool
> const & reg
= option
.Value
;
281 value
= reg
.Value
? OUString("yes") : OUString("no");
285 printf_line( "is registered", value
, level
+ 1 );
287 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
288 xPackage
->getPackageType() );
289 OSL_ASSERT( xPackageType
.is() );
290 if (xPackageType
.is()) {
291 printf_line( "Media-Type", xPackageType
->getMediaType(), level
+ 1 );
293 printf_line( "Description", xPackage
->getDescription(), level
+ 1 );
294 if (xPackage
->isBundle()) {
295 Sequence
< Reference
<deployment::XPackage
> > seq(
296 xPackage
->getBundle( Reference
<task::XAbortChannel
>(), xCmdEnv
) );
297 printf_space( level
+ 1 );
298 dp_misc::writeConsole("bundled Packages: {\n");
299 ::std::vector
<Reference
<deployment::XPackage
> >vec_bundle
;
300 ::comphelper::sequenceToContainer(vec_bundle
, seq
);
301 printf_packages( vec_bundle
, ::std::vector
<bool>(vec_bundle
.size()),
302 xCmdEnv
, level
+ 2 );
303 printf_space( level
+ 1 );
304 dp_misc::writeConsole("}\n");
310 void printf_unaccepted_licenses(
311 Reference
<deployment::XPackage
> const & ext
)
314 dp_misc::getIdentifier(ext
) );
315 printf_line( "Identifier", id
, 0 );
317 dp_misc::writeConsole("License not accepted\n\n");
321 void printf_packages(
322 ::std::vector
< Reference
<deployment::XPackage
> > const & allExtensions
,
323 ::std::vector
<bool> const & vecUnaccepted
,
324 Reference
<XCommandEnvironment
> const & xCmdEnv
, sal_Int32 level
)
326 OSL_ASSERT(allExtensions
.size() == vecUnaccepted
.size());
328 if (allExtensions
.empty())
330 printf_space( level
);
331 dp_misc::writeConsole("<none>\n");
335 typedef ::std::vector
< Reference
<deployment::XPackage
> >::const_iterator I_EXT
;
337 for (I_EXT i
= allExtensions
.begin(); i
!= allExtensions
.end(); ++i
, ++index
)
339 if (vecUnaccepted
[index
])
340 printf_unaccepted_licenses(*i
);
342 printf_package( *i
, xCmdEnv
, level
);
343 dp_misc::writeConsole("\n");
353 Reference
<XComponentContext
> bootstrapStandAlone()
355 Reference
<XComponentContext
> xContext
=
356 ::cppu::defaultBootstrap_InitialComponentContext();
358 Reference
<lang::XMultiServiceFactory
> xServiceManager(
359 xContext
->getServiceManager(), UNO_QUERY_THROW
);
360 // set global process service factory used by unotools config helpers
361 ::comphelper::setProcessServiceFactory( xServiceManager
);
363 // Initialize the UCB (for backwards compatibility, in case some code still
364 // uses plain createInstance w/o args directly to obtain an instance):
365 UniversalContentBroker::create( xContext
);
371 Reference
<XComponentContext
> connectToOffice(
372 Reference
<XComponentContext
> const & xLocalComponentContext
,
375 Sequence
<OUString
> args( 3 );
376 args
[ 0 ] = "--nologo";
377 args
[ 1 ] = "--nodefault";
379 OUString
pipeId( ::dp_misc::generateRandomPipeId() );
381 buf
.appendAscii( "--accept=pipe,name=" );
382 buf
.append( pipeId
);
383 buf
.appendAscii( ";urp;" );
384 args
[ 2 ] = buf
.makeStringAndClear();
385 OUString
appURL( getExecutableDir() + "/soffice" );
389 dp_misc::writeConsole(
390 "Raising process: " + appURL
+
391 "\nArguments: --nologo --nodefault " + args
[2] +
395 ::dp_misc::raiseProcess( appURL
, args
);
398 dp_misc::writeConsole("OK. Connecting...");
400 OSL_ASSERT( buf
.isEmpty() );
401 buf
.appendAscii( "uno:pipe,name=" );
402 buf
.append( pipeId
);
403 buf
.appendAscii( ";urp;StarOffice.ComponentContext" );
404 Reference
<XComponentContext
> xRet(
405 ::dp_misc::resolveUnoURL(
406 buf
.makeStringAndClear(), xLocalComponentContext
),
409 dp_misc::writeConsole("OK.\n");
416 /** returns the path to the lock file used by unopkg.
417 @return the path. An empty string signifies an error.
419 OUString
getLockFilePath()
422 OUString
sBootstrap("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}");
423 rtl::Bootstrap::expandMacros(sBootstrap
);
425 if (::osl::File::E_None
== ::osl::File::getAbsoluteFileURL(
426 sBootstrap
, ".lock", sAbs
))
428 if (::osl::File::E_None
==
429 ::osl::File::getSystemPathFromFileURL(sAbs
, sBootstrap
))
438 Reference
<XComponentContext
> getUNO(
439 bool verbose
, bool shared
, bool bGui
,
440 Reference
<XComponentContext
> & out_localContext
)
442 // do not create any user data (for the root user) in --shared mode:
445 OUString("CFG_CacheUrl"),
449 // hold lock during process runtime:
450 static ::desktop::Lockfile
s_lockfile( false /* no IPC server */ );
451 Reference
<XComponentContext
> xComponentContext( bootstrapStandAlone() );
452 out_localContext
= xComponentContext
;
453 if (::dp_misc::office_is_running()) {
454 xComponentContext
.set(
455 connectToOffice( xComponentContext
, verbose
) );
459 if (! s_lockfile
.check( 0 ))
461 OUString
sMsg(ResId(RID_STR_CONCURRENTINSTANCE
, *DeploymentResMgr::get()));
462 //Create this string before we call DeInitVCL, because this will kill
464 OUString
sError(ResId(RID_STR_UNOPKG_ERROR
, *DeploymentResMgr::get()));
466 sMsg
+= "\n" + getLockFilePath();
470 //We show a message box or print to the console that there
471 //is another instance already running
473 throw RuntimeException( "Cannot initialize VCL!" );
475 ScopedVclPtrInstance
< WarningBox
> warn(nullptr, WB_OK
| WB_DEF_OK
, sMsg
);
476 warn
->SetText(utl::ConfigManager::getProductName());
483 throw LockFileException(sError
+ sMsg
);
487 return xComponentContext
;
492 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */