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