1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_desktop.hxx"
31 #include "deployment.hrc"
32 #include "unopkg_shared.h"
33 #include "dp_identifier.hxx"
34 #include "../../deployment/gui/dp_gui.hrc"
35 #include "../../app/lockfile.hxx"
36 #include "vcl/svapp.hxx"
37 #include "vcl/msgbox.hxx"
38 #include "rtl/bootstrap.hxx"
39 #include "rtl/strbuf.hxx"
40 #include "rtl/ustrbuf.hxx"
41 #include "osl/process.h"
42 #include "osl/file.hxx"
43 #include "osl/thread.hxx"
44 #include "tools/getprocessworkingdir.hxx"
45 #include "ucbhelper/contentbroker.hxx"
46 #include "ucbhelper/configurationkeys.hxx"
47 #include "unotools/processfactory.hxx"
48 #include "unotools/configmgr.hxx"
49 #include "com/sun/star/lang/XMultiServiceFactory.hpp"
50 #include "cppuhelper/bootstrap.hxx"
51 #include "comphelper/sequence.hxx"
54 using ::rtl::OUString
;
56 using namespace ::com::sun::star
;
57 using namespace ::com::sun::star::uno
;
58 using namespace ::com::sun::star::ucb
;
62 bool getLockFilePath(OUString
& out
);
64 ::rtl::OUString
toString( OptionInfo
const * info
)
66 OSL_ASSERT( info
!= 0 );
67 ::rtl::OUStringBuffer buf
;
68 buf
.appendAscii("--");
69 buf
.appendAscii(info
->m_name
);
70 if (info
->m_short_option
!= '\0')
72 buf
.appendAscii(" (short -" );
73 buf
.append(info
->m_short_option
);
76 if (info
->m_has_argument
)
77 buf
.appendAscii(" <argument>" );
78 return buf
.makeStringAndClear();
81 //==============================================================================
82 OptionInfo
const * getOptionInfo(
83 OptionInfo
const * list
,
84 OUString
const & opt
, sal_Unicode copt
)
86 for ( ; list
->m_name
!= 0; ++list
)
88 OptionInfo
const & option_info
= *list
;
89 if (opt
.getLength() > 0)
92 option_info
.m_name
, option_info
.m_name_length
) &&
93 (copt
== '\0' || copt
== option_info
.m_short_option
))
100 OSL_ASSERT( copt
!= '\0' );
101 if (copt
== option_info
.m_short_option
)
107 OSL_ENSURE( 0, ::rtl::OUStringToOString(
108 opt
, osl_getThreadTextEncoding() ).getStr() );
112 //==============================================================================
113 bool isOption( OptionInfo
const * option_info
, sal_uInt32
* pIndex
)
115 OSL_ASSERT( option_info
!= 0 );
116 if (osl_getCommandArgCount() <= *pIndex
)
120 osl_getCommandArg( *pIndex
, &arg
.pData
);
121 sal_Int32 len
= arg
.getLength();
123 if (len
< 2 || arg
[ 0 ] != '-')
126 if (len
== 2 && arg
[ 1 ] == option_info
->m_short_option
)
129 dp_misc::TRACE(OUSTR(__FILE__
": identified option \'")
130 + OUSTR("\'") + OUString( option_info
->m_short_option
) + OUSTR("\n"));
133 if (arg
[ 1 ] == '-' && rtl_ustr_ascii_compare(
134 arg
.pData
->buffer
+ 2, option_info
->m_name
) == 0)
137 dp_misc::TRACE(OUSTR( __FILE__
": identified option \'")
138 + OUString::createFromAscii(option_info
->m_name
) + OUSTR("\'\n"));
143 //==============================================================================
145 bool isBootstrapVariable(sal_uInt32
* pIndex
)
147 OSL_ASSERT(osl_getCommandArgCount() >= *pIndex
);
150 osl_getCommandArg(*pIndex
, &arg
.pData
);
151 if (arg
.matchAsciiL("-env:", 5))
159 //==============================================================================
161 OUString
* pValue
, OptionInfo
const * option_info
, sal_uInt32
* pIndex
)
163 if (isOption( option_info
, pIndex
))
165 if (*pIndex
< osl_getCommandArgCount())
167 OSL_ASSERT( pValue
!= 0 );
168 osl_getCommandArg( *pIndex
, &pValue
->pData
);
169 dp_misc::TRACE(OUSTR( __FILE__
": argument value: ")
170 + *pValue
+ OUSTR("\n"));
179 //##############################################################################
182 struct ExecutableDir
: public rtl::StaticWithInit
<
183 const OUString
, ExecutableDir
> {
184 const OUString
operator () () {
186 if (osl_getExecutableFile( &path
.pData
) != osl_Process_E_None
) {
187 throw RuntimeException(
188 OUSTR("cannot locate executable directory!"),0 );
190 return path
.copy( 0, path
.lastIndexOf( '/' ) );
193 struct ProcessWorkingDir
: public rtl::StaticWithInit
<
194 const OUString
, ProcessWorkingDir
> {
195 const OUString
operator () () {
197 tools::getProcessWorkingDir(&workingDir
);
203 //==============================================================================
204 OUString
const & getExecutableDir()
206 return ExecutableDir::get();
209 //==============================================================================
210 OUString
const & getProcessWorkingDir()
212 return ProcessWorkingDir::get();
215 //==============================================================================
216 OUString
makeAbsoluteFileUrl(
217 OUString
const & sys_path
, OUString
const & base_url
, bool throw_exc
)
219 // system path to file url
221 oslFileError rc
= osl_getFileURLFromSystemPath( sys_path
.pData
, &file_url
.pData
);
222 if ( rc
!= osl_File_E_None
) {
224 if ( osl_getSystemPathFromFileURL( sys_path
.pData
, &tempPath
.pData
) == osl_File_E_None
)
230 throw RuntimeException(
231 OUSTR("cannot get file url from system path: ") +
232 sys_path
, Reference
< XInterface
>() );
237 if (osl_getAbsoluteFileURL(
238 base_url
.pData
, file_url
.pData
, &abs
.pData
) != osl_File_E_None
)
241 ::rtl::OUStringBuffer buf
;
242 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(
243 "making absolute file url failed: \"") );
244 buf
.append( base_url
);
245 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(
246 "\" (base-url) and \"") );
247 buf
.append( file_url
);
248 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" (file-url)!") );
249 throw RuntimeException(
250 buf
.makeStringAndClear(), Reference
< XInterface
>() );
254 return abs
[ abs
.getLength() -1 ] == '/'
255 ? abs
.copy( 0, abs
.getLength() -1 ) : abs
;
258 //##############################################################################
262 //------------------------------------------------------------------------------
263 inline void printf_space( sal_Int32 space
)
266 dp_misc::writeConsole(" ");
269 //------------------------------------------------------------------------------
271 OUString
const & name
, OUString
const & value
, sal_Int32 level
)
273 printf_space( level
);
274 dp_misc::writeConsole(name
+ OUSTR(": ") + value
+ OUSTR("\n"));
277 //------------------------------------------------------------------------------
279 Reference
<deployment::XPackage
> const & xPackage
,
280 Reference
<XCommandEnvironment
> const & xCmdEnv
, sal_Int32 level
)
282 beans::Optional
< OUString
> id(
284 ? beans::Optional
< OUString
>(
285 true, dp_misc::getIdentifier( xPackage
) )
286 : xPackage
->getIdentifier() );
288 printf_line( OUSTR("Identifier"), id
.Value
, level
);
289 OUString
version(xPackage
->getVersion());
290 if (version
.getLength() != 0)
291 printf_line( OUSTR("Version"), version
, level
+ 1 );
292 printf_line( OUSTR("URL"), xPackage
->getURL(), level
+ 1 );
294 beans::Optional
< beans::Ambiguous
<sal_Bool
> > option(
295 xPackage
->isRegistered( Reference
<task::XAbortChannel
>(), xCmdEnv
) );
297 if (option
.IsPresent
) {
298 beans::Ambiguous
<sal_Bool
> const & reg
= option
.Value
;
300 value
= OUSTR("unknown");
302 value
= reg
.Value
? OUSTR("yes") : OUSTR("no");
305 value
= OUSTR("n/a");
306 printf_line( OUSTR("is registered"), value
, level
+ 1 );
308 const Reference
<deployment::XPackageTypeInfo
> xPackageType(
309 xPackage
->getPackageType() );
310 OSL_ASSERT( xPackageType
.is() );
311 if (xPackageType
.is()) {
312 printf_line( OUSTR("Media-Type"),
313 xPackageType
->getMediaType(), level
+ 1 );
315 printf_line( OUSTR("Description"), xPackage
->getDescription(), level
+ 1 );
316 if (xPackage
->isBundle()) {
317 Sequence
< Reference
<deployment::XPackage
> > seq(
318 xPackage
->getBundle( Reference
<task::XAbortChannel
>(), xCmdEnv
) );
319 printf_space( level
+ 1 );
320 dp_misc::writeConsole("bundled Packages: {\n");
321 ::std::vector
<Reference
<deployment::XPackage
> >vec_bundle
;
322 ::comphelper::sequenceToContainer(vec_bundle
, seq
);
323 printf_packages( vec_bundle
, ::std::vector
<bool>(vec_bundle
.size()),
324 xCmdEnv
, level
+ 2 );
325 printf_space( level
+ 1 );
326 dp_misc::writeConsole("}\n");
332 void printf_unaccepted_licenses(
333 Reference
<deployment::XPackage
> const & ext
)
336 dp_misc::getIdentifier(ext
) );
337 printf_line( OUSTR("Identifier"), id
, 0 );
339 dp_misc::writeConsole(OUSTR("License not accepted\n\n"));
342 //==============================================================================
343 void printf_packages(
344 ::std::vector
< Reference
<deployment::XPackage
> > const & allExtensions
,
345 ::std::vector
<bool> const & vecUnaccepted
,
346 Reference
<XCommandEnvironment
> const & xCmdEnv
, sal_Int32 level
)
348 OSL_ASSERT(allExtensions
.size() == vecUnaccepted
.size());
350 if (allExtensions
.size() == 0)
352 printf_space( level
);
353 dp_misc::writeConsole("<none>\n");
357 typedef ::std::vector
< Reference
<deployment::XPackage
> >::const_iterator I_EXT
;
359 for (I_EXT i
= allExtensions
.begin(); i
!= allExtensions
.end(); i
++, index
++)
361 if (vecUnaccepted
[index
])
362 printf_unaccepted_licenses(*i
);
364 printf_package( *i
, xCmdEnv
, level
);
365 dp_misc::writeConsole(OUSTR("\n"));
371 //##############################################################################
375 //------------------------------------------------------------------------------
376 Reference
<XComponentContext
> bootstrapStandAlone(
377 DisposeGuard
& disposeGuard
, bool /*verbose */)
379 Reference
<XComponentContext
> xContext
=
380 ::cppu::defaultBootstrap_InitialComponentContext();
382 // assure disposing of local component context:
384 Reference
<lang::XComponent
>( xContext
, UNO_QUERY
) );
386 Reference
<lang::XMultiServiceFactory
> xServiceManager(
387 xContext
->getServiceManager(), UNO_QUERY_THROW
);
388 // set global process service factory used by unotools config helpers
389 ::utl::setProcessServiceFactory( xServiceManager
);
391 // initialize the ucbhelper ucb,
392 // because the package implementation uses it
393 Sequence
<Any
> ucb_args( 2 );
394 ucb_args
[ 0 ] <<= OUSTR(UCB_CONFIGURATION_KEY1_LOCAL
);
395 ucb_args
[ 1 ] <<= OUSTR(UCB_CONFIGURATION_KEY2_OFFICE
);
396 if (! ::ucbhelper::ContentBroker::initialize( xServiceManager
, ucb_args
))
397 throw RuntimeException( OUSTR("cannot initialize UCB!"), 0 );
399 disposeGuard
.setDeinitUCB();
403 //------------------------------------------------------------------------------
404 Reference
<XComponentContext
> connectToOffice(
405 Reference
<XComponentContext
> const & xLocalComponentContext
,
408 Sequence
<OUString
> args( 3 );
409 args
[ 0 ] = OUSTR("-nologo");
410 args
[ 1 ] = OUSTR("-nodefault");
412 OUString
pipeId( ::dp_misc::generateRandomPipeId() );
413 ::rtl::OUStringBuffer buf
;
414 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("-accept=pipe,name=") );
415 buf
.append( pipeId
);
416 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(";urp;") );
417 args
[ 2 ] = buf
.makeStringAndClear();
418 OUString
appURL( getExecutableDir() + OUSTR("/soffice") );
422 dp_misc::writeConsole(
423 OUSTR("Raising process: ") +
425 OUSTR("\nArguments: -nologo -nodefault ") +
430 ::dp_misc::raiseProcess( appURL
, args
);
433 dp_misc::writeConsole("Ok. Connecting...");
435 OSL_ASSERT( buf
.getLength() == 0 );
436 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("uno:pipe,name=") );
437 buf
.append( pipeId
);
438 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(
439 ";urp;StarOffice.ComponentContext") );
440 Reference
<XComponentContext
> xRet(
441 ::dp_misc::resolveUnoURL(
442 buf
.makeStringAndClear(), xLocalComponentContext
),
445 dp_misc::writeConsole("Ok.\n");
452 /** returns the path to the lock file used by unopkg.
453 @return the path. An empty string signifies an error.
455 OUString
getLockFilePath()
458 OUString
sBootstrap(RTL_CONSTASCII_USTRINGPARAM("${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}"));
459 rtl::Bootstrap::expandMacros(sBootstrap
);
461 if (::osl::File::E_None
== ::osl::File::getAbsoluteFileURL(
462 sBootstrap
, OUSTR(".lock"), sAbs
))
464 if (::osl::File::E_None
==
465 ::osl::File::getSystemPathFromFileURL(sAbs
, sBootstrap
))
473 //==============================================================================
474 Reference
<XComponentContext
> getUNO(
475 DisposeGuard
& disposeGuard
, bool verbose
, bool shared
, bool bGui
,
476 Reference
<XComponentContext
> & out_localContext
)
478 // do not create any user data (for the root user) in --shared mode:
481 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CFG_CacheUrl")),
485 // hold lock during process runtime:
486 static ::desktop::Lockfile
s_lockfile( false /* no IPC server */ );
487 Reference
<XComponentContext
> xComponentContext(
488 bootstrapStandAlone( disposeGuard
, verbose
) );
489 out_localContext
= xComponentContext
;
490 if (::dp_misc::office_is_running()) {
491 xComponentContext
.set(
492 connectToOffice( xComponentContext
, verbose
) );
496 if (! s_lockfile
.check( 0 ))
498 String
sMsg(ResId(RID_STR_CONCURRENTINSTANCE
, *DeploymentResMgr::get()));
499 //Create this string before we call DeInitVCL, because this will kill
501 String
sError(ResId(RID_STR_UNOPKG_ERROR
, *DeploymentResMgr::get()));
503 sMsg
= sMsg
+ OUSTR("\n") + getLockFilePath();
507 //We show a message box or print to the console that there
508 //is another instance already running
509 if ( ! InitVCL( Reference
<lang::XMultiServiceFactory
>(
510 xComponentContext
->getServiceManager(),
512 throw RuntimeException( OUSTR("Cannot initialize VCL!"),
515 WarningBox
warn(NULL
, WB_OK
| WB_DEF_OK
, sMsg
);
516 warn
.SetText(::utl::ConfigManager::GetDirectConfigProperty(
517 ::utl::ConfigManager::PRODUCTNAME
).get
<OUString
>());
524 throw LockFileException(
525 OUSTR("\n") + sError
+ sMsg
+ OUSTR("\n"));
529 return xComponentContext
;
532 //Determines if a folder does not contains a folder.
533 //Return false may also mean that the status could not be determined
534 //because some error occurred.
535 bool hasNoFolder(OUString
const & folderUrl
)
538 OUString url
= folderUrl
;
539 ::rtl::Bootstrap::expandMacros(url
);
540 ::osl::Directory
dir(url
);
541 osl::File::RC rc
= dir
.open();
542 if (rc
== osl::File::E_None
)
544 bool bFolderExist
= false;
545 osl::DirectoryItem i
;
546 osl::File::RC rcNext
= osl::File::E_None
;
547 while ( (rcNext
= dir
.getNextItem(i
)) == osl::File::E_None
)
549 osl::FileStatus
stat(FileStatusMask_Type
);
550 if (i
.getFileStatus(stat
) == osl::File::E_None
)
552 if (stat
.getFileType() == osl::FileStatus::Directory
)
560 dp_misc::writeConsole(
561 OUSTR("unopkg: Error while investigating ") + url
+ OUSTR("\n"));
564 i
= osl::DirectoryItem();
567 if (rcNext
== osl::File::E_NOENT
||
568 rcNext
== osl::File::E_None
)
575 dp_misc::writeConsole(
576 OUSTR("unopkg: Error while investigating ") + url
+ OUSTR("\n"));
583 dp_misc::writeConsole(
584 OUSTR("unopkg: Error while investigating ") + url
+ OUSTR("\n"));
589 void removeFolder(OUString
const & folderUrl
)
591 OUString url
= folderUrl
;
592 ::rtl::Bootstrap::expandMacros(url
);
593 ::osl::Directory
dir(url
);
594 ::osl::File::RC rc
= dir
.open();
595 if (rc
== osl::File::E_None
)
597 ::osl::DirectoryItem i
;
598 ::osl::File::RC rcNext
= ::osl::File::E_None
;
599 while ( (rcNext
= dir
.getNextItem(i
)) == ::osl::File::E_None
)
601 ::osl::FileStatus
stat(FileStatusMask_Type
| FileStatusMask_FileURL
);
602 if (i
.getFileStatus(stat
) == ::osl::File::E_None
)
604 ::osl::FileStatus::Type t
= stat
.getFileType();
605 if (t
== ::osl::FileStatus::Directory
)
608 removeFolder(stat
.getFileURL());
610 else if (t
== ::osl::FileStatus::Regular
)
613 ::osl::File::remove(stat
.getFileURL());
622 dp_misc::writeConsole(
623 OUSTR("unopkg: Error while investigating ") + url
+ OUSTR("\n"));
626 i
= ::osl::DirectoryItem();
629 ::osl::Directory::remove(url
);
631 else if (rc
!= osl::File::E_NOENT
)
633 dp_misc::writeConsole(
634 OUSTR("unopkg: Error while removing ") + url
+ OUSTR("\n"));