1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 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. 14 * 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). 20 * 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. 25 * 26 ************************************************************************/ 27 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <sys/stat.h> 33 34 #ifdef LINUX 35 #define __USE_GNU 36 #endif 37 #include <dlfcn.h> 38 39 #include "cppuhelper/findsofficepath.h" 40 #include "rtl/string.h" 41 #include "sal/types.h" 42 43 char const* getPath(); 44 char* createCommandName( char* argv0 ); 45 46 const int SEPARATOR = '/'; 47 const char* PATHSEPARATOR = ":"; 48 49 50 /* 51 * The main function implements a loader for applications which use UNO. 52 * 53 * <p>This code runs on the Unix/Linux platforms only.</p> 54 * 55 * <p>The main function detects a UNO installation on the system and adds the 56 * relevant directories of the installation to the LD_LIBRARY_PATH environment 57 * variable. After that, the application process is loaded and started, whereby 58 * the new process inherits the environment of the calling process, including 59 * the modified LD_LIBRARY_PATH environment variable. The application's 60 * executable name must be the same as the name of this executable, prefixed 61 * by '_'.</p> 62 * <p>On MACOSX DYLD_LIBRARY_PATH is used instead of LD_LIBRARY_PATH!<p> 63 * 64 * <p>A UNO installation can be specified by the user by setting the UNO_PATH 65 * environment variable to the program directory of the UNO installation. 66 * If no installation is specified by the user, the default installation on 67 * the system will be taken. The default installation is found from the 68 * PATH environment variable. This requires that the 'soffice' executable or 69 * a symbolic link is in one of the directories listed in the PATH environment 70 * variable.</p> 71 */ 72 int main( int argc, char *argv[] ) 73 { 74 char const* path; 75 char* cmdname; 76 77 (void) argc; /* avoid warning about unused parameter */ 78 79 /* get the path of the UNO installation */ 80 path = getPath(); 81 82 if ( path != NULL ) 83 { 84 #ifdef MACOSX 85 static const char* ENVVARNAME = "DYLD_LIBRARY_PATH"; 86 #else 87 static const char* ENVVARNAME = "LD_LIBRARY_PATH"; 88 #endif 89 char * libpath; 90 int freeLibpath; 91 92 char* value; 93 char* envstr; 94 int size; 95 96 size_t pathlen = strlen(path); 97 struct stat stat; 98 int ret; 99 char * unoinfo = malloc( 100 pathlen + RTL_CONSTASCII_LENGTH("/unoinfo") + 1); 101 /*TODO: overflow */ 102 if (unoinfo == NULL) { 103 fprintf(stderr, "Error: out of memory!\n"); 104 exit(EXIT_FAILURE); 105 } 106 strcpy(unoinfo, path); 107 strcpy( 108 unoinfo + pathlen, 109 "/unoinfo" + (pathlen == 0 || path[pathlen - 1] != '/' ? 0 : 1)); 110 ret = lstat(unoinfo, &stat); 111 free(unoinfo); 112 113 if (ret == 0) { 114 char * cmd = malloc( 115 2 * pathlen + RTL_CONSTASCII_LENGTH("/unoinfo c++") + 1); 116 /*TODO: overflow */ 117 char const * p; 118 char * q; 119 FILE * f; 120 size_t n = 1000; 121 size_t old = 0; 122 if (cmd == NULL) { 123 fprintf(stderr, "Error: out of memory!\n"); 124 exit(EXIT_FAILURE); 125 } 126 p = path; 127 q = cmd; 128 while (*p != '\0') { 129 *q++ = '\\'; 130 *q++ = *p++; 131 } 132 if (p == path || p[-1] != '/') { 133 *q++ = '/'; 134 } 135 strcpy(q, "unoinfo c++"); 136 f = popen(cmd, "r"); 137 free(cmd); 138 if (f == NULL) 139 { 140 fprintf(stderr, "Error: calling unoinfo failed!\n"); 141 exit(EXIT_FAILURE); 142 } 143 libpath = NULL; 144 for (;;) { 145 size_t m; 146 libpath = realloc(libpath, n); 147 if (libpath == NULL) { 148 fprintf( 149 stderr, 150 "Error: out of memory reading unoinfo output!\n"); 151 exit(EXIT_FAILURE); 152 } 153 m = fread(libpath + old, 1, n - old - 1, f); 154 if (m != n - old - 1) { 155 if (ferror(f)) { 156 fprintf(stderr, "Error: cannot read unoinfo output!\n"); 157 exit(EXIT_FAILURE); 158 } 159 libpath[old + m] = '\0'; 160 break; 161 } 162 if (n >= SAL_MAX_SIZE / 2) { 163 fprintf( 164 stderr, 165 "Error: out of memory reading unoinfo output!\n"); 166 exit(EXIT_FAILURE); 167 } 168 old = n - 1; 169 n *= 2; 170 } 171 if (pclose(f) != 0) { 172 fprintf(stderr, "Error: executing unoinfo failed!\n"); 173 exit(EXIT_FAILURE); 174 } 175 freeLibpath = 1; 176 } 177 else 178 { 179 /* Assume an old OOo 2.x installation without unoinfo: */ 180 libpath = (char *) path; 181 freeLibpath = 0; 182 } 183 184 value = getenv( ENVVARNAME ); 185 186 size = strlen( ENVVARNAME ) + strlen( "=" ) + strlen( libpath ) + 1; 187 if ( value != NULL ) 188 size += strlen( PATHSEPARATOR ) + strlen( value ); 189 envstr = (char*) malloc( size ); 190 strcpy( envstr, ENVVARNAME ); 191 strcat( envstr, "=" ); 192 strcat( envstr, libpath ); 193 if ( freeLibpath != 0 ) 194 { 195 free( libpath ); 196 } 197 if ( value != NULL ) 198 { 199 strcat( envstr, PATHSEPARATOR ); 200 strcat( envstr, value ); 201 } 202 putenv( envstr ); 203 } 204 else 205 { 206 fprintf( stderr, "Warning: no UNO installation found!\n" ); 207 fflush( stderr ); 208 } 209 210 /* set the executable name for the application process */ 211 cmdname = createCommandName( argv[0] ); 212 argv[0] = cmdname; 213 214 /* 215 * create the application process; 216 * if successful, execvp doesn't return to the calling process 217 */ 218 execvp( cmdname, argv ); 219 fprintf( stderr, "Error: execvp failed!\n" ); 220 fflush( stderr ); 221 222 return 0; 223 } 224 225 /* 226 * Gets the path of a UNO installation. 227 * 228 * @return the installation path or NULL, if no installation was specified or 229 * found, or if an error occured 230 */ 231 char const* getPath() 232 { 233 char const* path = cppuhelper_detail_findSofficePath(); 234 235 if ( path == NULL ) 236 { 237 fprintf( stderr, "Warning: getting path from PATH environment " 238 "variable failed!\n" ); 239 fflush( stderr ); 240 } 241 242 return path; 243 } 244 245 /* 246 * Creates the application's executable file name. 247 * 248 * <p>The application's executable file name is the name of this executable 249 * prefixed by '_'.</p> 250 * 251 * @param argv0 specifies the argv[0] parameter of the main function 252 * 253 * @return the application's executable file name or NULL, if an error occured 254 */ 255 char* createCommandName( char* argv0 ) 256 { 257 const char* CMDPREFIX = "_"; 258 const char* prgname = NULL; 259 260 char* cmdname = NULL; 261 char* sep = NULL; 262 Dl_info dl_info; 263 int pos; 264 265 /* get the executable file name from argv0 */ 266 prgname = argv0; 267 268 /* 269 * if argv0 doesn't contain an absolute path name, try to get the absolute 270 * path name from dladdr; note that this only works for Solaris, not for 271 * Linux 272 */ 273 if ( argv0 != NULL && *argv0 != SEPARATOR && 274 dladdr( (void*) &createCommandName, &dl_info ) && 275 dl_info.dli_fname != NULL && *dl_info.dli_fname == SEPARATOR ) 276 { 277 prgname = dl_info.dli_fname; 278 } 279 280 /* prefix the executable file name by '_' */ 281 if ( prgname != NULL ) 282 { 283 cmdname = (char*) malloc( strlen( prgname ) + strlen( CMDPREFIX ) + 1 ); 284 sep = strrchr( prgname, SEPARATOR ); 285 if ( sep != NULL ) 286 { 287 pos = ++sep - prgname; 288 strncpy( cmdname, prgname, pos ); 289 cmdname[ pos ] = '\0'; 290 strcat( cmdname, CMDPREFIX ); 291 strcat( cmdname, sep ); 292 } 293 else 294 { 295 strcpy( cmdname, CMDPREFIX ); 296 strcat( cmdname, prgname ); 297 } 298 } 299 300 return cmdname; 301 } 302