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