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.append("--");
60 buf.appendAscii(info->m_name);
61 if (info->m_short_option != '\0')
62 {
63 buf.append(" (short -" );
64 buf.append(info->m_short_option );
65 buf.append(")");
66 }
67 if (info->m_has_argument)
68 buf.append(" <argument>" );
69 return buf.makeStringAndClear();
70}
71
72
74 OptionInfo const * list,
75 OUString const & opt )
76{
77 for ( ; list->m_name != nullptr; ++list )
78 {
79 OptionInfo const & option_info = *list;
80 if (!opt.isEmpty())
81 {
82 if (opt.equalsAsciiL(
83 option_info.m_name, option_info.m_name_length ))
84 {
85 return &option_info;
86 }
87 }
88 }
89 SAL_WARN( "desktop", opt );
90 return nullptr;
91}
92
93
94bool isOption( OptionInfo const * option_info, sal_uInt32 * pIndex )
95{
96 assert(option_info != nullptr);
97 if (osl_getCommandArgCount() <= *pIndex)
98 return false;
99
100 OUString arg;
101 osl_getCommandArg( *pIndex, &arg.pData );
102 sal_Int32 len = arg.getLength();
103
104 if (len < 2 || arg[ 0 ] != '-')
105 return false;
106
107 if (len == 2 && arg[ 1 ] == option_info->m_short_option)
108 {
109 ++(*pIndex);
110 dp_misc::TRACE(__FILE__ ": identified option \'\'"
111 + OUStringChar( option_info->m_short_option ) + "\n");
112 return true;
113 }
114 if (arg[ 1 ] == '-' && rtl_ustr_ascii_compare(
115 arg.pData->buffer + 2, option_info->m_name ) == 0)
116 {
117 ++(*pIndex);
118 dp_misc::TRACE(__FILE__ ": identified option \'"
119 + OUString::createFromAscii(option_info->m_name) + "\'\n");
120 return true;
121 }
122 return false;
123}
124
125
126bool isBootstrapVariable(sal_uInt32 * pIndex)
127{
128 OSL_ASSERT(osl_getCommandArgCount() >= *pIndex);
129
130 OUString arg;
131 osl_getCommandArg(*pIndex, &arg.pData);
132 if (arg.match("-env:"))
133 {
134 ++(*pIndex);
135 return true;
136 }
137 return false;
138}
139
140
142 OUString * pValue, OptionInfo const * option_info, sal_uInt32 * pIndex )
143{
144 if (isOption( option_info, pIndex ))
145 {
146 if (*pIndex < osl_getCommandArgCount())
147 {
148 OSL_ASSERT( pValue != nullptr );
149 osl_getCommandArg( *pIndex, &pValue->pData );
150 dp_misc::TRACE(__FILE__ ": argument value: "
151 + *pValue + "\n");
152 ++(*pIndex);
153 return true;
154 }
155 --(*pIndex);
156 }
157 return false;
158}
159
160
161OUString const & getExecutableDir()
162{
163 static const OUString EXEC =
164 []()
165 {
166 OUString path;
167 if (osl_getExecutableFile( &path.pData ) != osl_Process_E_None) {
168 throw RuntimeException("cannot locate executable directory!",nullptr);
169 }
170 return path.copy( 0, path.lastIndexOf( '/' ) );
171 }();
172 return EXEC;
173}
174
175
176OUString const & getProcessWorkingDir()
177{
178 static const OUString WORKING =
179 []()
180 {
181 OUString workingDir;
183 return workingDir;
184 }();
185 return WORKING;
186}
187
188
190 OUString const & sys_path, OUString const & base_url )
191{
192 // system path to file url
193 OUString file_url;
194 oslFileError rc = osl_getFileURLFromSystemPath( sys_path.pData, &file_url.pData );
195 if ( rc != osl_File_E_None) {
196 OUString tempPath;
197 if ( osl_getSystemPathFromFileURL( sys_path.pData, &tempPath.pData) != osl_File_E_None )
198 {
199 throw RuntimeException("cannot get file url from system path: " +
200 sys_path );
201 }
202 file_url = sys_path;
203 }
204
205 OUString abs;
206 if (osl_getAbsoluteFileURL(
207 base_url.pData, file_url.pData, &abs.pData ) != osl_File_E_None)
208 {
209 throw RuntimeException(
210 "making absolute file url failed: \"" + base_url
211 + "\" (base-url) and \"" + file_url + "\" (file-url)!" );
212 }
213 return abs[ abs.getLength() -1 ] == '/'
214 ? abs.copy( 0, abs.getLength() -1 ) : abs;
215}
216
217
218namespace {
219
220
221void printf_space( sal_Int32 space )
222{
223 while (space--)
225}
226
227
228void printf_line(
229 std::u16string_view name, std::u16string_view value, sal_Int32 level )
230{
231 printf_space( level );
232 dp_misc::writeConsole(Concat2View(OUString::Concat(name) + ": " + value + "\n"));
233}
234
235
236void printf_package(
237 Reference<deployment::XPackage> const & xPackage,
238 Reference<XCommandEnvironment> const & xCmdEnv, sal_Int32 level )
239{
240 beans::Optional< OUString > id(
241 level == 0
242 ? beans::Optional< OUString >(
243 true, dp_misc::getIdentifier( xPackage ) )
244 : xPackage->getIdentifier() );
245 if (id.IsPresent)
246 printf_line( u"Identifier", id.Value, level );
247 OUString version(xPackage->getVersion());
248 if (!version.isEmpty())
249 printf_line( u"Version", version, level + 1 );
250 printf_line( u"URL", xPackage->getURL(), level + 1 );
251
252 beans::Optional< beans::Ambiguous<sal_Bool> > option(
253 xPackage->isRegistered( Reference<task::XAbortChannel>(), xCmdEnv ) );
254 OUString value;
255 if (option.IsPresent) {
256 beans::Ambiguous<sal_Bool> const & reg = option.Value;
257 if (reg.IsAmbiguous)
258 value = "unknown";
259 else
260 value = reg.Value ? std::u16string_view(u"yes") : std::u16string_view(u"no");
261 }
262 else
263 value = "n/a";
264 printf_line( u"is registered", value, level + 1 );
265
266 const Reference<deployment::XPackageTypeInfo> xPackageType(
267 xPackage->getPackageType() );
268 OSL_ASSERT( xPackageType.is() );
269 if (xPackageType.is()) {
270 printf_line( u"Media-Type", xPackageType->getMediaType(), level + 1 );
271 }
272 printf_line( u"Description", xPackage->getDescription(), level + 1 );
273 if (!xPackage->isBundle())
274 return;
275
276 Sequence< Reference<deployment::XPackage> > seq(
277 xPackage->getBundle( Reference<task::XAbortChannel>(), xCmdEnv ) );
278 printf_space( level + 1 );
279 dp_misc::writeConsole(u"bundled Packages: {\n");
280 std::vector<Reference<deployment::XPackage> >vec_bundle;
281 ::comphelper::sequenceToContainer(vec_bundle, seq);
282 printf_packages( vec_bundle, std::vector<bool>(vec_bundle.size()),
283 xCmdEnv, level + 2 );
284 printf_space( level + 1 );
285 dp_misc::writeConsole(u"}\n");
286}
287
288} // anon namespace
289
291 Reference<deployment::XPackage> const & ext)
292{
293 OUString id(
295 printf_line( u"Identifier", id, 0 );
296 printf_space(1);
297 dp_misc::writeConsole(u"License not accepted\n\n");
298}
299
300
302 std::vector< Reference<deployment::XPackage> > const & allExtensions,
303 std::vector<bool> const & vecUnaccepted,
304 Reference<XCommandEnvironment> const & xCmdEnv, sal_Int32 level )
305{
306 OSL_ASSERT(allExtensions.size() == vecUnaccepted.size());
307
308 if (allExtensions.empty())
309 {
310 printf_space( level );
311 dp_misc::writeConsole(u"<none>\n");
312 }
313 else
314 {
315 int index = 0;
316 for (auto const& extension : allExtensions)
317 {
318 if (vecUnaccepted[index])
320 else
321 printf_package( extension, xCmdEnv, level );
323 ++index;
324 }
325 }
326}
327
328
329namespace {
330
331
332Reference<XComponentContext> bootstrapStandAlone()
333{
334 Reference<XComponentContext> xContext =
335 ::cppu::defaultBootstrap_InitialComponentContext();
336
337 Reference<lang::XMultiServiceFactory> xServiceManager(
338 xContext->getServiceManager(), UNO_QUERY_THROW );
339 // set global process service factory used by unotools config helpers
340 ::comphelper::setProcessServiceFactory( xServiceManager );
341
342 // Initialize the UCB (for backwards compatibility, in case some code still
343 // uses plain createInstance w/o args directly to obtain an instance):
345
346 return xContext;
347}
348
349
350Reference<XComponentContext> connectToOffice(
351 Reference<XComponentContext> const & xLocalComponentContext,
352 bool verbose )
353{
354 OUString pipeId( ::dp_misc::generateRandomPipeId() );
355 OUString acceptArg = "--accept=pipe,name=" + pipeId + ";urp;";
356
357 Sequence<OUString> args { "--nologo", "--nodefault", acceptArg };
358 OUString appURL( getExecutableDir() + "/soffice" );
359
360 if (verbose)
361 {
362 dp_misc::writeConsole(Concat2View(
363 "Raising process: " + appURL +
364 "\nArguments: --nologo --nodefault " + args[2] +
365 "\n"));
366 }
367
368 ::dp_misc::raiseProcess( appURL, args );
369
370 if (verbose)
371 dp_misc::writeConsole(u"OK. Connecting...");
372
373 OUString sUnoUrl = "uno:pipe,name=" + pipeId + ";urp;StarOffice.ComponentContext";
374 Reference<XComponentContext> xRet(
376 sUnoUrl, xLocalComponentContext ),
377 UNO_QUERY_THROW );
378 if (verbose)
379 dp_misc::writeConsole(u"OK.\n");
380
381 return xRet;
382}
383
384} // anon namespace
385
389static OUString getLockFilePath()
390{
391 OUString ret;
392 OUString sBootstrap("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}");
393 rtl::Bootstrap::expandMacros(sBootstrap);
394 OUString sAbs;
395 if (::osl::File::E_None == ::osl::File::getAbsoluteFileURL(
396 sBootstrap, ".lock", sAbs))
397 {
398 if (::osl::File::E_None ==
399 ::osl::File::getSystemPathFromFileURL(sAbs, sBootstrap))
400 {
401 ret = sBootstrap;
402 }
403 }
404
405 return ret;
406}
407
408Reference<XComponentContext> getUNO(
409 bool verbose, bool bGui, const OUString& sTempDir,
410 Reference<XComponentContext> & out_localContext)
411{
412 // do not create any user data (for the root user) in --shared mode:
413 if (!sTempDir.isEmpty())
414 rtl::Bootstrap::set("UserInstallation", sTempDir);
415
416 // hold lock during process runtime:
417 static ::desktop::Lockfile s_lockfile( false /* no IPC server */ );
418 Reference<XComponentContext> xComponentContext( bootstrapStandAlone() );
419 out_localContext = xComponentContext;
421 xComponentContext.set(
422 connectToOffice( xComponentContext, verbose ) );
423 }
424 else
425 {
426 if (! s_lockfile.check( nullptr ))
427 {
428 OUString sMsg(DpResId(RID_STR_CONCURRENTINSTANCE));
429 OUString sError(DpResId(RID_STR_UNOPKG_ERROR));
430
431 sMsg += "\n" + getLockFilePath();
432
433 if (bGui)
434 {
435 //We show a message box or print to the console that there
436 //is another instance already running
437 if ( ! InitVCL() )
438 throw RuntimeException( "Cannot initialize VCL!" );
439 {
440 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(nullptr,
441 VclMessageType::Warning, VclButtonsType::Ok,
442 sMsg));
443 xWarn->set_title(utl::ConfigManager::getProductName());
444 xWarn->run();
445 }
446 DeInitVCL();
447 }
448
449 throw LockFileException(sError + sMsg);
450 }
451 }
452
453 return xComponentContext;
454}
455
456}
457
458/* 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:556
float u
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2638
#define SAL_WARN(area, stream)
bool office_is_running()
Definition: dp_misc.cxx:332
void TRACE(OUString const &sText)
print the text to the console in a debug build.
Definition: dp_misc.cxx:487
Reference< XInterface > resolveUnoURL(OUString const &connectString, Reference< XComponentContext > const &xLocalContext, AbortChannel const *abortChannel)
Definition: dp_misc.cxx:430
OUString generateRandomPipeId()
Definition: dp_misc.cxx:411
void writeConsole(std::u16string_view sText)
writes the argument string to the console.
Definition: dp_misc.cxx:464
oslProcess raiseProcess(OUString const &appURL, Sequence< OUString > const &args)
Definition: dp_misc.cxx:375
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:94
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:73
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