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