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 <sal/config.h>
22 #include <string_view>
24 #include <config_folders.h>
26 #include <vcl/svapp.hxx>
27 #include <vcl/weld.hxx>
28 #include <rtl/bootstrap.hxx>
29 #include <rtl/ustrbuf.hxx>
30 #include <sal/log.hxx>
31 #include <osl/process.h>
32 #include <osl/file.hxx>
33 #include <unotools/configmgr.hxx>
34 #include <unotools/bootstrap.hxx>
35 #include <cppuhelper/bootstrap.hxx>
36 #include <comphelper/sequence.hxx>
37 #include <comphelper/processfactory.hxx>
39 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
40 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
42 #include <strings.hrc>
43 #include "unopkg_shared.h"
44 #include <dp_identifier.hxx>
46 #include <dp_shared.hxx>
47 #include <lockfile.hxx>
49 using namespace ::com::sun::star
;
50 using namespace ::com::sun::star::uno
;
51 using namespace ::com::sun::star::ucb
;
55 OUString
toString( OptionInfo
const * info
)
57 assert(info
!= nullptr);
58 OUStringBuffer
buf("--");
59 buf
.appendAscii(info
->m_name
);
60 if (info
->m_short_option
!= '\0')
62 buf
.append(" (short -" + OUStringChar(info
->m_short_option
) + ")");
64 if (info
->m_has_argument
)
65 buf
.append(" <argument>" );
66 return buf
.makeStringAndClear();
70 OptionInfo
const * getOptionInfo(
71 OptionInfo
const * list
,
72 OUString
const & opt
)
74 for ( ; list
->m_name
!= nullptr; ++list
)
76 OptionInfo
const & option_info
= *list
;
80 option_info
.m_name
, option_info
.m_name_length
))
86 SAL_WARN( "desktop", opt
);
91 bool isOption( OptionInfo
const * option_info
, sal_uInt32
* pIndex
)
93 assert(option_info
!= nullptr);
94 if (osl_getCommandArgCount() <= *pIndex
)
98 osl_getCommandArg( *pIndex
, &arg
.pData
);
99 sal_Int32 len
= arg
.getLength();
101 if (len
< 2 || arg
[ 0 ] != '-')
104 if (len
== 2 && arg
[ 1 ] == option_info
->m_short_option
)
107 dp_misc::TRACE(__FILE__
": identified option \'\'"
108 + OUStringChar( option_info
->m_short_option
) + "\n");
111 if (arg
[ 1 ] == '-' && rtl_ustr_ascii_compare(
112 arg
.pData
->buffer
+ 2, option_info
->m_name
) == 0)
115 dp_misc::TRACE(__FILE__
": identified option \'"
116 + OUString::createFromAscii(option_info
->m_name
) + "\'\n");
123 bool isBootstrapVariable(sal_uInt32
* pIndex
)
125 OSL_ASSERT(osl_getCommandArgCount() >= *pIndex
);
128 osl_getCommandArg(*pIndex
, &arg
.pData
);
129 if (arg
.match("-env:"))
139 OUString
* pValue
, OptionInfo
const * option_info
, sal_uInt32
* pIndex
)
141 if (isOption( option_info
, pIndex
))
143 if (*pIndex
< osl_getCommandArgCount())
145 assert(pValue
!= nullptr);
146 osl_getCommandArg( *pIndex
, &pValue
->pData
);
147 dp_misc::TRACE(__FILE__
": argument value: "
158 static OUString
getExecutableDirInit()
161 if (osl_getExecutableFile( &path
.pData
) != osl_Process_E_None
) {
162 throw RuntimeException(u
"cannot locate executable directory!"_ustr
,nullptr);
164 return path
.copy( 0, path
.lastIndexOf( '/' ) );
167 OUString
const & getExecutableDir()
169 static const OUString EXEC
= getExecutableDirInit();
174 OUString
const & getProcessWorkingDir()
176 static const OUString WORKING
=
180 utl::Bootstrap::getProcessWorkingDir(workingDir
);
187 OUString
makeAbsoluteFileUrl(
188 OUString
const & sys_path
, OUString
const & base_url
)
190 // system path to file url
192 oslFileError rc
= osl_getFileURLFromSystemPath( sys_path
.pData
, &file_url
.pData
);
193 if ( rc
!= osl_File_E_None
) {
195 if ( osl_getSystemPathFromFileURL( sys_path
.pData
, &tempPath
.pData
) != osl_File_E_None
)
197 throw RuntimeException("cannot get file url from system path: " +
204 if (osl_getAbsoluteFileURL(
205 base_url
.pData
, file_url
.pData
, &abs
.pData
) != osl_File_E_None
)
207 throw RuntimeException(
208 "making absolute file url failed: \"" + base_url
209 + "\" (base-url) and \"" + file_url
+ "\" (file-url)!" );
211 return abs
[ abs
.getLength() -1 ] == '/'
212 ? abs
.copy( 0, abs
.getLength() -1 ) : abs
;
219 void printf_space( sal_Int32 space
)
222 dp_misc::writeConsole(u
" ");
227 std::u16string_view name
, std::u16string_view value
, sal_Int32 level
)
229 printf_space( level
);
230 dp_misc::writeConsole(Concat2View(OUString::Concat(name
) + ": " + value
+ "\n"));
235 Reference
<deployment::XPackage
> const & xPackage
,
236 Reference
<XCommandEnvironment
> const & xCmdEnv
, sal_Int32 level
)
238 beans::Optional
< OUString
> id(
240 ? beans::Optional
< OUString
>(
241 true, dp_misc::getIdentifier( xPackage
) )
242 : xPackage
->getIdentifier() );
244 printf_line( u
"Identifier", id
.Value
, level
);
245 OUString
version(xPackage
->getVersion());
246 if (!version
.isEmpty())
247 printf_line( u
"Version", version
, level
+ 1 );
248 printf_line( u
"URL", xPackage
->getURL(), level
+ 1 );
250 beans::Optional
< beans::Ambiguous
<sal_Bool
> > option(
251 xPackage
->isRegistered( Reference
<task::XAbortChannel
>(), xCmdEnv
) );
253 if (option
.IsPresent
) {
254 beans::Ambiguous
<sal_Bool
> const & reg
= option
.Value
;
258 value
= reg
.Value
? std::u16string_view(u
"yes") : std::u16string_view(u
"no");
262 printf_line( u
"is registered", value
, level
+ 1 );
264 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
265 xPackage
->getPackageType() );
266 OSL_ASSERT( xPackageType
.is() );
267 if (xPackageType
.is()) {
268 printf_line( u
"Media-Type", xPackageType
->getMediaType(), level
+ 1 );
270 printf_line( u
"Description", xPackage
->getDescription(), level
+ 1 );
271 if (!xPackage
->isBundle())
274 Sequence
< Reference
<deployment::XPackage
> > seq(
275 xPackage
->getBundle( Reference
<task::XAbortChannel
>(), xCmdEnv
) );
276 printf_space( level
+ 1 );
277 dp_misc::writeConsole(u
"bundled Packages: {\n");
278 std::vector
<Reference
<deployment::XPackage
> >vec_bundle
;
279 ::comphelper::sequenceToContainer(vec_bundle
, seq
);
280 printf_packages( vec_bundle
, std::vector
<bool>(vec_bundle
.size()),
281 xCmdEnv
, level
+ 2 );
282 printf_space( level
+ 1 );
283 dp_misc::writeConsole(u
"}\n");
288 static void printf_unaccepted_licenses(
289 Reference
<deployment::XPackage
> const & ext
)
292 dp_misc::getIdentifier(ext
) );
293 printf_line( u
"Identifier", id
, 0 );
295 dp_misc::writeConsole(u
"License not accepted\n\n");
299 void printf_packages(
300 std::vector
< Reference
<deployment::XPackage
> > const & allExtensions
,
301 std::vector
<bool> const & vecUnaccepted
,
302 Reference
<XCommandEnvironment
> const & xCmdEnv
, sal_Int32 level
)
304 OSL_ASSERT(allExtensions
.size() == vecUnaccepted
.size());
306 if (allExtensions
.empty())
308 printf_space( level
);
309 dp_misc::writeConsole(u
"<none>\n");
314 for (auto const& extension
: allExtensions
)
316 if (vecUnaccepted
[index
])
317 printf_unaccepted_licenses(extension
);
319 printf_package( extension
, xCmdEnv
, level
);
320 dp_misc::writeConsole(u
"\n");
330 Reference
<XComponentContext
> bootstrapStandAlone()
332 Reference
<XComponentContext
> xContext
=
333 ::cppu::defaultBootstrap_InitialComponentContext();
335 Reference
<lang::XMultiServiceFactory
> xServiceManager(
336 xContext
->getServiceManager(), UNO_QUERY_THROW
);
337 // set global process service factory used by unotools config helpers
338 ::comphelper::setProcessServiceFactory( xServiceManager
);
340 // Initialize the UCB (for backwards compatibility, in case some code still
341 // uses plain createInstance w/o args directly to obtain an instance):
342 UniversalContentBroker::create( xContext
);
348 Reference
<XComponentContext
> connectToOffice(
349 Reference
<XComponentContext
> const & xLocalComponentContext
,
352 OUString
pipeId( ::dp_misc::generateRandomPipeId() );
354 Sequence
<OUString
> args
{ u
"--nologo"_ustr
, u
"--nodefault"_ustr
, "--accept=pipe,name=" + pipeId
+ ";urp;" };
355 OUString
appURL( getExecutableDir() + "/soffice" );
359 dp_misc::writeConsole(Concat2View(
360 "Raising process: " + appURL
+
361 "\nArguments: --nologo --nodefault " + args
[2] +
365 ::dp_misc::raiseProcess( appURL
, args
);
368 dp_misc::writeConsole(u
"OK. Connecting...");
370 OUString sUnoUrl
= "uno:pipe,name=" + pipeId
+ ";urp;StarOffice.ComponentContext";
371 Reference
<XComponentContext
> xRet(
372 ::dp_misc::resolveUnoURL(
373 sUnoUrl
, xLocalComponentContext
),
376 dp_misc::writeConsole(u
"OK.\n");
383 /** returns the path to the lock file used by unopkg.
384 @return the path. An empty string signifies an error.
386 static OUString
getLockFilePath()
389 OUString
sBootstrap(u
"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}"_ustr
);
390 rtl::Bootstrap::expandMacros(sBootstrap
);
392 if (::osl::File::E_None
== ::osl::File::getAbsoluteFileURL(
393 sBootstrap
, u
".lock"_ustr
, sAbs
))
395 if (::osl::File::E_None
==
396 ::osl::File::getSystemPathFromFileURL(sAbs
, sBootstrap
))
405 Reference
<XComponentContext
> getUNO(
406 bool verbose
, bool bGui
, const OUString
& sTempDir
,
407 Reference
<XComponentContext
> & out_localContext
)
409 // do not create any user data (for the root user) in --shared mode:
410 if (!sTempDir
.isEmpty())
411 rtl::Bootstrap::set(u
"UserInstallation"_ustr
, sTempDir
);
413 // hold lock during process runtime:
414 static ::desktop::Lockfile
s_lockfile( false /* no IPC server */ );
415 Reference
<XComponentContext
> xComponentContext( bootstrapStandAlone() );
416 out_localContext
= xComponentContext
;
417 if (::dp_misc::office_is_running()) {
418 xComponentContext
.set(
419 connectToOffice( xComponentContext
, verbose
) );
423 if (! s_lockfile
.check( nullptr ))
425 OUString
sMsg(DpResId(RID_STR_CONCURRENTINSTANCE
));
426 OUString
sError(DpResId(RID_STR_UNOPKG_ERROR
));
428 sMsg
+= "\n" + getLockFilePath();
432 //We show a message box or print to the console that there
433 //is another instance already running
435 throw RuntimeException( u
"Cannot initialize VCL!"_ustr
);
437 std::unique_ptr
<weld::MessageDialog
> xWarn(Application::CreateMessageDialog(nullptr,
438 VclMessageType::Warning
, VclButtonsType::Ok
,
440 xWarn
->set_title(utl::ConfigManager::getProductName());
446 throw LockFileException(sError
+ sMsg
);
450 return xComponentContext
;
455 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */