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