LibreOffice Module desktop (master) 1
unopkg_misc.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <string_view>
23
24#include <config_folders.h>
25
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>
38
39#include <com/sun/star/lang/XMultiServiceFactory.hpp>
40#include <com/sun/star/ucb/UniversalContentBroker.hpp>
41
42#include <strings.hrc>
43#include "unopkg_shared.h"
44#include <dp_identifier.hxx>
45#include <dp_misc.h>
46#include <dp_shared.hxx>
47#include <lockfile.hxx>
48
49using namespace ::com::sun::star;
50using namespace ::com::sun::star::uno;
51using namespace ::com::sun::star::ucb;
52
53namespace unopkg {
54
55OUString toString( OptionInfo const * info )
56{
57 assert(info != nullptr);
58 OUStringBuffer buf("--");
59 buf.appendAscii(info->m_name);
60 if (info->m_short_option != '\0')
61 {
62 buf.append(" (short -" + OUStringChar(info->m_short_option) + ")");
63 }
64 if (info->m_has_argument)
65 buf.append(" <argument>" );
66 return buf.makeStringAndClear();
67}
68
69
71 OptionInfo const * list,
72 OUString const & opt )
73{
74 for ( ; list->m_name != nullptr; ++list )
75 {
76 OptionInfo const & option_info = *list;
77 if (!opt.isEmpty())
78 {
79 if (opt.equalsAsciiL(
80 option_info.m_name, option_info.m_name_length ))
81 {
82 return &option_info;
83 }
84 }
85 }
86 SAL_WARN( "desktop", opt );
87 return nullptr;
88}
89
90
91bool isOption( OptionInfo const * option_info, sal_uInt32 * pIndex )
92{
93 assert(option_info != nullptr);
94 if (osl_getCommandArgCount() <= *pIndex)
95 return false;
96
97 OUString arg;
98 osl_getCommandArg( *pIndex, &arg.pData );
99 sal_Int32 len = arg.getLength();
100
101 if (len < 2 || arg[ 0 ] != '-')
102 return false;
103
104 if (len == 2 && arg[ 1 ] == option_info->m_short_option)
105 {
106 ++(*pIndex);
107 dp_misc::TRACE(__FILE__ ": identified option \'\'"
108 + OUStringChar( option_info->m_short_option ) + "\n");
109 return true;
110 }
111 if (arg[ 1 ] == '-' && rtl_ustr_ascii_compare(
112 arg.pData->buffer + 2, option_info->m_name ) == 0)
113 {
114 ++(*pIndex);
115 dp_misc::TRACE(__FILE__ ": identified option \'"
116 + OUString::createFromAscii(option_info->m_name) + "\'\n");
117 return true;
118 }
119 return false;
120}
121
122
123bool isBootstrapVariable(sal_uInt32 * pIndex)
124{
125 OSL_ASSERT(osl_getCommandArgCount() >= *pIndex);
126
127 OUString arg;
128 osl_getCommandArg(*pIndex, &arg.pData);
129 if (arg.match("-env:"))
130 {
131 ++(*pIndex);
132 return true;
133 }
134 return false;
135}
136
137
139 OUString * pValue, OptionInfo const * option_info, sal_uInt32 * pIndex )
140{
141 if (isOption( option_info, pIndex ))
142 {
143 if (*pIndex < osl_getCommandArgCount())
144 {
145 OSL_ASSERT( pValue != nullptr );
146 osl_getCommandArg( *pIndex, &pValue->pData );
147 dp_misc::TRACE(__FILE__ ": argument value: "
148 + *pValue + "\n");
149 ++(*pIndex);
150 return true;
151 }
152 --(*pIndex);
153 }
154 return false;
155}
156
157
158OUString const & getExecutableDir()
159{
160 static const OUString EXEC =
161 []()
162 {
163 OUString path;
164 if (osl_getExecutableFile( &path.pData ) != osl_Process_E_None) {
165 throw RuntimeException("cannot locate executable directory!",nullptr);
166 }
167 return path.copy( 0, path.lastIndexOf( '/' ) );
168 }();
169 return EXEC;
170}
171
172
173OUString const & getProcessWorkingDir()
174{
175 static const OUString WORKING =
176 []()
177 {
178 OUString workingDir;
180 return workingDir;
181 }();
182 return WORKING;
183}
184
185
187 OUString const & sys_path, OUString const & base_url )
188{
189 // system path to file url
190 OUString file_url;
191 oslFileError rc = osl_getFileURLFromSystemPath( sys_path.pData, &file_url.pData );
192 if ( rc != osl_File_E_None) {
193 OUString tempPath;
194 if ( osl_getSystemPathFromFileURL( sys_path.pData, &tempPath.pData) != osl_File_E_None )
195 {
196 throw RuntimeException("cannot get file url from system path: " +
197 sys_path );
198 }
199 file_url = sys_path;
200 }
201
202 OUString abs;
203 if (osl_getAbsoluteFileURL(
204 base_url.pData, file_url.pData, &abs.pData ) != osl_File_E_None)
205 {
206 throw RuntimeException(
207 "making absolute file url failed: \"" + base_url
208 + "\" (base-url) and \"" + file_url + "\" (file-url)!" );
209 }
210 return abs[ abs.getLength() -1 ] == '/'
211 ? abs.copy( 0, abs.getLength() -1 ) : abs;
212}
213
214
215namespace {
216
217
218void printf_space( sal_Int32 space )
219{
220 while (space--)
222}
223
224
225void printf_line(
226 std::u16string_view name, std::u16string_view value, sal_Int32 level )
227{
228 printf_space( level );
229 dp_misc::writeConsole(Concat2View(OUString::Concat(name) + ": " + value + "\n"));
230}
231
232
233void printf_package(
234 Reference<deployment::XPackage> const & xPackage,
235 Reference<XCommandEnvironment> const & xCmdEnv, sal_Int32 level )
236{
237 beans::Optional< OUString > id(
238 level == 0
239 ? beans::Optional< OUString >(
240 true, dp_misc::getIdentifier( xPackage ) )
241 : xPackage->getIdentifier() );
242 if (id.IsPresent)
243 printf_line( u"Identifier", id.Value, level );
244 OUString version(xPackage->getVersion());
245 if (!version.isEmpty())
246 printf_line( u"Version", version, level + 1 );
247 printf_line( u"URL", xPackage->getURL(), level + 1 );
248
249 beans::Optional< beans::Ambiguous<sal_Bool> > option(
250 xPackage->isRegistered( Reference<task::XAbortChannel>(), xCmdEnv ) );
251 OUString value;
252 if (option.IsPresent) {
253 beans::Ambiguous<sal_Bool> const & reg = option.Value;
254 if (reg.IsAmbiguous)
255 value = "unknown";
256 else
257 value = reg.Value ? std::u16string_view(u"yes") : std::u16string_view(u"no");
258 }
259 else
260 value = "n/a";
261 printf_line( u"is registered", value, level + 1 );
262
263 const Reference<deployment::XPackageTypeInfo> xPackageType(
264 xPackage->getPackageType() );
265 OSL_ASSERT( xPackageType.is() );
266 if (xPackageType.is()) {
267 printf_line( u"Media-Type", xPackageType->getMediaType(), level + 1 );
268 }
269 printf_line( u"Description", xPackage->getDescription(), level + 1 );
270 if (!xPackage->isBundle())
271 return;
272
273 Sequence< Reference<deployment::XPackage> > seq(
274 xPackage->getBundle( Reference<task::XAbortChannel>(), xCmdEnv ) );
275 printf_space( level + 1 );
276 dp_misc::writeConsole(u"bundled Packages: {\n");
277 std::vector<Reference<deployment::XPackage> >vec_bundle;
278 ::comphelper::sequenceToContainer(vec_bundle, seq);
279 printf_packages( vec_bundle, std::vector<bool>(vec_bundle.size()),
280 xCmdEnv, level + 2 );
281 printf_space( level + 1 );
282 dp_misc::writeConsole(u"}\n");
283}
284
285} // anon namespace
286
288 Reference<deployment::XPackage> const & ext)
289{
290 OUString id(
292 printf_line( u"Identifier", id, 0 );
293 printf_space(1);
294 dp_misc::writeConsole(u"License not accepted\n\n");
295}
296
297
299 std::vector< Reference<deployment::XPackage> > const & allExtensions,
300 std::vector<bool> const & vecUnaccepted,
301 Reference<XCommandEnvironment> const & xCmdEnv, sal_Int32 level )
302{
303 OSL_ASSERT(allExtensions.size() == vecUnaccepted.size());
304
305 if (allExtensions.empty())
306 {
307 printf_space( level );
308 dp_misc::writeConsole(u"<none>\n");
309 }
310 else
311 {
312 int index = 0;
313 for (auto const& extension : allExtensions)
314 {
315 if (vecUnaccepted[index])
317 else
318 printf_package( extension, xCmdEnv, level );
320 ++index;
321 }
322 }
323}
324
325
326namespace {
327
328
329Reference<XComponentContext> bootstrapStandAlone()
330{
331 Reference<XComponentContext> xContext =
332 ::cppu::defaultBootstrap_InitialComponentContext();
333
334 Reference<lang::XMultiServiceFactory> xServiceManager(
335 xContext->getServiceManager(), UNO_QUERY_THROW );
336 // set global process service factory used by unotools config helpers
337 ::comphelper::setProcessServiceFactory( xServiceManager );
338
339 // Initialize the UCB (for backwards compatibility, in case some code still
340 // uses plain createInstance w/o args directly to obtain an instance):
342
343 return xContext;
344}
345
346
347Reference<XComponentContext> connectToOffice(
348 Reference<XComponentContext> const & xLocalComponentContext,
349 bool verbose )
350{
351 OUString pipeId( ::dp_misc::generateRandomPipeId() );
352 OUString acceptArg = "--accept=pipe,name=" + pipeId + ";urp;";
353
354 Sequence<OUString> args { "--nologo", "--nodefault", acceptArg };
355 OUString appURL( getExecutableDir() + "/soffice" );
356
357 if (verbose)
358 {
359 dp_misc::writeConsole(Concat2View(
360 "Raising process: " + appURL +
361 "\nArguments: --nologo --nodefault " + args[2] +
362 "\n"));
363 }
364
365 ::dp_misc::raiseProcess( appURL, args );
366
367 if (verbose)
368 dp_misc::writeConsole(u"OK. Connecting...");
369
370 OUString sUnoUrl = "uno:pipe,name=" + pipeId + ";urp;StarOffice.ComponentContext";
371 Reference<XComponentContext> xRet(
373 sUnoUrl, xLocalComponentContext ),
374 UNO_QUERY_THROW );
375 if (verbose)
376 dp_misc::writeConsole(u"OK.\n");
377
378 return xRet;
379}
380
381} // anon namespace
382
386static OUString getLockFilePath()
387{
388 OUString ret;
389 OUString sBootstrap("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}");
390 rtl::Bootstrap::expandMacros(sBootstrap);
391 OUString sAbs;
392 if (::osl::File::E_None == ::osl::File::getAbsoluteFileURL(
393 sBootstrap, ".lock", sAbs))
394 {
395 if (::osl::File::E_None ==
396 ::osl::File::getSystemPathFromFileURL(sAbs, sBootstrap))
397 {
398 ret = sBootstrap;
399 }
400 }
401
402 return ret;
403}
404
405Reference<XComponentContext> getUNO(
406 bool verbose, bool bGui, const OUString& sTempDir,
407 Reference<XComponentContext> & out_localContext)
408{
409 // do not create any user data (for the root user) in --shared mode:
410 if (!sTempDir.isEmpty())
411 rtl::Bootstrap::set("UserInstallation", sTempDir);
412
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;
418 xComponentContext.set(
419 connectToOffice( xComponentContext, verbose ) );
420 }
421 else
422 {
423 if (! s_lockfile.check( nullptr ))
424 {
425 OUString sMsg(DpResId(RID_STR_CONCURRENTINSTANCE));
426 OUString sError(DpResId(RID_STR_UNOPKG_ERROR));
427
428 sMsg += "\n" + getLockFilePath();
429
430 if (bGui)
431 {
432 //We show a message box or print to the console that there
433 //is another instance already running
434 if ( ! InitVCL() )
435 throw RuntimeException( "Cannot initialize VCL!" );
436 {
437 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(nullptr,
438 VclMessageType::Warning, VclButtonsType::Ok,
439 sMsg));
440 xWarn->set_title(utl::ConfigManager::getProductName());
441 xWarn->run();
442 }
443 DeInitVCL();
444 }
445
446 throw LockFileException(sError + sMsg);
447 }
448 }
449
450 return xComponentContext;
451}
452
453}
454
455/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
static bool getProcessWorkingDir(OUString &rUrl)
static OUString getProductName()
Any value
#define SAL_CONFIGFILE(name)
OUString DpResId(TranslateId aId)
Definition: dp_misc.cxx:555
float u
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2642
#define SAL_WARN(area, stream)
bool office_is_running()
Definition: dp_misc.cxx:331
void TRACE(OUString const &sText)
print the text to the console in a debug build.
Definition: dp_misc.cxx:486
Reference< XInterface > resolveUnoURL(OUString const &connectString, Reference< XComponentContext > const &xLocalContext, AbortChannel const *abortChannel)
Definition: dp_misc.cxx:429
OUString generateRandomPipeId()
Definition: dp_misc.cxx:410
void writeConsole(std::u16string_view sText)
writes the argument string to the console.
Definition: dp_misc.cxx:463
oslProcess raiseProcess(OUString const &appURL, Sequence< OUString > const &args)
Definition: dp_misc.cxx:374
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getIdentifier(css::uno::Reference< css::deployment::XPackage > const &package)
Gets the identifier of a package.
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
index
bool verbose
args
Reference< XComponentContext > getUNO(bool verbose, bool bGui, const OUString &sTempDir, Reference< XComponentContext > &out_localContext)
OUString toString(OptionInfo const *info)
Definition: unopkg_misc.cxx:55
bool isOption(OptionInfo const *option_info, sal_uInt32 *pIndex)
Definition: unopkg_misc.cxx:91
OUString const & getProcessWorkingDir()
static OUString getLockFilePath()
returns the path to the lock file used by unopkg.
bool readArgument(OUString *pValue, OptionInfo const *option_info, sal_uInt32 *pIndex)
OUString const & getExecutableDir()
void printf_packages(std::vector< Reference< deployment::XPackage > > const &allExtensions, std::vector< bool > const &vecUnaccepted, Reference< XCommandEnvironment > const &xCmdEnv, sal_Int32 level)
static void printf_unaccepted_licenses(Reference< deployment::XPackage > const &ext)
bool isBootstrapVariable(sal_uInt32 *pIndex)
checks if an argument is a bootstrap variable.
OptionInfo const * getOptionInfo(OptionInfo const *list, OUString const &opt)
Definition: unopkg_misc.cxx:70
OUString makeAbsoluteFileUrl(OUString const &sys_path, OUString const &base_url)
SwNodeOffset abs(const SwNodeOffset &a)
sal_uInt32 m_name_length
Definition: unopkg_shared.h:36
char const * m_name
Definition: unopkg_shared.h:35
sal_Unicode m_short_option
Definition: unopkg_shared.h:37
VCL_DLLPUBLIC bool InitVCL()
VCL_DLLPUBLIC void DeInitVCL()
JCOPY_OPTION option