merged tag ooo/DEV300_m102
[LibreOffice.git] / desktop / source / pkgchk / unopkg / unopkg_misc.cxx
blobf6773b768062a7f833b58dc2d2807902479699a3
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"
52 #include <stdio.h>
54 using ::rtl::OUString;
55 using ::rtl::OString;
56 using namespace ::com::sun::star;
57 using namespace ::com::sun::star::uno;
58 using namespace ::com::sun::star::ucb;
60 namespace unopkg {
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 );
74 buf.appendAscii(")");
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)
91 if (opt.equalsAsciiL(
92 option_info.m_name, option_info.m_name_length ) &&
93 (copt == '\0' || copt == option_info.m_short_option))
95 return &option_info;
98 else
100 OSL_ASSERT( copt != '\0' );
101 if (copt == option_info.m_short_option)
103 return &option_info;
107 OSL_ENSURE( 0, ::rtl::OUStringToOString(
108 opt, osl_getThreadTextEncoding() ).getStr() );
109 return 0;
112 //==============================================================================
113 bool isOption( OptionInfo const * option_info, sal_uInt32 * pIndex )
115 OSL_ASSERT( option_info != 0 );
116 if (osl_getCommandArgCount() <= *pIndex)
117 return false;
119 OUString arg;
120 osl_getCommandArg( *pIndex, &arg.pData );
121 sal_Int32 len = arg.getLength();
123 if (len < 2 || arg[ 0 ] != '-')
124 return false;
126 if (len == 2 && arg[ 1 ] == option_info->m_short_option)
128 ++(*pIndex);
129 dp_misc::TRACE(OUSTR(__FILE__": identified option \'")
130 + OUSTR("\'") + OUString( option_info->m_short_option ) + OUSTR("\n"));
131 return true;
133 if (arg[ 1 ] == '-' && rtl_ustr_ascii_compare(
134 arg.pData->buffer + 2, option_info->m_name ) == 0)
136 ++(*pIndex);
137 dp_misc::TRACE(OUSTR( __FILE__": identified option \'")
138 + OUString::createFromAscii(option_info->m_name) + OUSTR("\'\n"));
139 return true;
141 return false;
143 //==============================================================================
145 bool isBootstrapVariable(sal_uInt32 * pIndex)
147 OSL_ASSERT(osl_getCommandArgCount() >= *pIndex);
149 OUString arg;
150 osl_getCommandArg(*pIndex, &arg.pData);
151 if (arg.matchAsciiL("-env:", 5))
153 ++(*pIndex);
154 return true;
156 return false;
159 //==============================================================================
160 bool readArgument(
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"));
171 ++(*pIndex);
172 return true;
174 --(*pIndex);
176 return false;
179 //##############################################################################
181 namespace {
182 struct ExecutableDir : public rtl::StaticWithInit<
183 const OUString, ExecutableDir> {
184 const OUString operator () () {
185 OUString path;
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 () () {
196 OUString workingDir;
197 tools::getProcessWorkingDir(&workingDir);
198 return workingDir;
201 } // anon namespace
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
220 OUString file_url;
221 oslFileError rc = osl_getFileURLFromSystemPath( sys_path.pData, &file_url.pData );
222 if ( rc != osl_File_E_None) {
223 OUString tempPath;
224 if ( osl_getSystemPathFromFileURL( sys_path.pData, &tempPath.pData) == osl_File_E_None )
226 file_url = sys_path;
228 else if (throw_exc)
230 throw RuntimeException(
231 OUSTR("cannot get file url from system path: ") +
232 sys_path, Reference< XInterface >() );
236 OUString abs;
237 if (osl_getAbsoluteFileURL(
238 base_url.pData, file_url.pData, &abs.pData ) != osl_File_E_None)
240 if (throw_exc) {
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 >() );
252 return OUString();
254 return abs[ abs.getLength() -1 ] == '/'
255 ? abs.copy( 0, abs.getLength() -1 ) : abs;
258 //##############################################################################
260 namespace {
262 //------------------------------------------------------------------------------
263 inline void printf_space( sal_Int32 space )
265 while (space--)
266 dp_misc::writeConsole(" ");
269 //------------------------------------------------------------------------------
270 void printf_line(
271 OUString const & name, OUString const & value, sal_Int32 level )
273 printf_space( level );
274 dp_misc::writeConsole(name + OUSTR(": ") + value + OUSTR("\n"));
277 //------------------------------------------------------------------------------
278 void printf_package(
279 Reference<deployment::XPackage> const & xPackage,
280 Reference<XCommandEnvironment> const & xCmdEnv, sal_Int32 level )
282 beans::Optional< OUString > id(
283 level == 0
284 ? beans::Optional< OUString >(
285 true, dp_misc::getIdentifier( xPackage ) )
286 : xPackage->getIdentifier() );
287 if (id.IsPresent)
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 ) );
296 OUString value;
297 if (option.IsPresent) {
298 beans::Ambiguous<sal_Bool> const & reg = option.Value;
299 if (reg.IsAmbiguous)
300 value = OUSTR("unknown");
301 else
302 value = reg.Value ? OUSTR("yes") : OUSTR("no");
304 else
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");
330 } // anon namespace
332 void printf_unaccepted_licenses(
333 Reference<deployment::XPackage> const & ext)
335 OUString id(
336 dp_misc::getIdentifier(ext) );
337 printf_line( OUSTR("Identifier"), id, 0 );
338 printf_space(1);
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");
355 else
357 typedef ::std::vector< Reference<deployment::XPackage> >::const_iterator I_EXT;
358 int index = 0;
359 for (I_EXT i = allExtensions.begin(); i != allExtensions.end(); i++, index++)
361 if (vecUnaccepted[index])
362 printf_unaccepted_licenses(*i);
363 else
364 printf_package( *i, xCmdEnv, level );
365 dp_misc::writeConsole(OUSTR("\n"));
371 //##############################################################################
373 namespace {
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:
383 disposeGuard.reset(
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();
400 return xContext;
403 //------------------------------------------------------------------------------
404 Reference<XComponentContext> connectToOffice(
405 Reference<XComponentContext> const & xLocalComponentContext,
406 bool verbose )
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") );
420 if (verbose)
422 dp_misc::writeConsole(
423 OUSTR("Raising process: ") +
424 appURL +
425 OUSTR("\nArguments: -nologo -nodefault ") +
426 args[2] +
427 OUSTR("\n"));
430 ::dp_misc::raiseProcess( appURL, args );
432 if (verbose)
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 ),
443 UNO_QUERY_THROW );
444 if (verbose)
445 dp_misc::writeConsole("Ok.\n");
447 return xRet;
450 } // anon namespace
452 /** returns the path to the lock file used by unopkg.
453 @return the path. An empty string signifies an error.
455 OUString getLockFilePath()
457 OUString ret;
458 OUString sBootstrap(RTL_CONSTASCII_USTRINGPARAM("${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}"));
459 rtl::Bootstrap::expandMacros(sBootstrap);
460 OUString sAbs;
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))
467 ret = sBootstrap;
471 return ret;
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:
479 if (shared) {
480 rtl::Bootstrap::set(
481 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CFG_CacheUrl")),
482 rtl::OUString());
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 ) );
494 else
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
500 //the ResMgr
501 String sError(ResId(RID_STR_UNOPKG_ERROR, *DeploymentResMgr::get()));
503 sMsg = sMsg + OUSTR("\n") + getLockFilePath();
505 if (bGui)
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(),
511 UNO_QUERY_THROW ) ))
512 throw RuntimeException( OUSTR("Cannot initialize VCL!"),
513 NULL );
515 WarningBox warn(NULL, WB_OK | WB_DEF_OK, sMsg);
516 warn.SetText(::utl::ConfigManager::GetDirectConfigProperty(
517 ::utl::ConfigManager::PRODUCTNAME).get<OUString>());
518 warn.SetIcon(0);
519 warn.Execute();
521 DeInitVCL();
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)
537 bool ret = false;
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)
554 bFolderExist = true;
555 break;
558 else
560 dp_misc::writeConsole(
561 OUSTR("unopkg: Error while investigating ") + url + OUSTR("\n"));
562 break;
564 i = osl::DirectoryItem();
567 if (rcNext == osl::File::E_NOENT ||
568 rcNext == osl::File::E_None)
570 if (!bFolderExist)
571 ret = true;
573 else
575 dp_misc::writeConsole(
576 OUSTR("unopkg: Error while investigating ") + url + OUSTR("\n"));
579 dir.close();
581 else
583 dp_misc::writeConsole(
584 OUSTR("unopkg: Error while investigating ") + url + OUSTR("\n"));
586 return ret;
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)
607 //remove folder
608 removeFolder(stat.getFileURL());
610 else if (t == ::osl::FileStatus::Regular)
612 //remove file
613 ::osl::File::remove(stat.getFileURL());
615 else
617 OSL_ASSERT(0);
620 else
622 dp_misc::writeConsole(
623 OUSTR("unopkg: Error while investigating ") + url + OUSTR("\n"));
624 break;
626 i = ::osl::DirectoryItem();
628 dir.close();
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"));