1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #include <stdlib.h> 25 #include <unistd.h> 26 #include <stdio.h> 27 #include <string.h> 28 #include <sys/stat.h> 29 30 #ifdef LINUX 31 #define __USE_GNU 32 #endif 33 #include <dlfcn.h> 34 35 #include "cppuhelper/findsofficepath.h" 36 #include "rtl/string.h" 37 #include "sal/types.h" 38 39 char const* getPath(); 40 char* createCommandName( char* argv0 ); 41 42 const int SEPARATOR = '/'; 43 const char* PATHSEPARATOR = ":"; 44 45 46 /* 47 * The main function implements a loader for applications which use UNO. 48 * 49 * <p>This code runs on the Unix/Linux platforms only.</p> 50 * 51 * <p>The main function detects a UNO installation on the system and adds the 52 * relevant directories of the installation to the LD_LIBRARY_PATH environment 53 * variable. After that, the application process is loaded and started, whereby 54 * the new process inherits the environment of the calling process, including 55 * the modified LD_LIBRARY_PATH environment variable. The application's 56 * executable name must be the same as the name of this executable, prefixed 57 * by '_'.</p> 58 * <p>On MACOSX DYLD_LIBRARY_PATH is used instead of LD_LIBRARY_PATH!<p> 59 * 60 * <p>A UNO installation can be specified by the user by setting the UNO_PATH 61 * environment variable to the program directory of the UNO installation. 62 * If no installation is specified by the user, the default installation on 63 * the system will be taken. The default installation is found from the 64 * PATH environment variable. This requires that the 'soffice' executable or 65 * a symbolic link is in one of the directories listed in the PATH environment 66 * variable.</p> 67 */ 68 int main( int argc, char *argv[] ) 69 { 70 char const* path; 71 char* cmdname; 72 73 (void) argc; /* avoid warning about unused parameter */ 74 75 /* get the path of the UNO installation */ 76 path = getPath(); 77 78 if ( path != NULL ) 79 { 80 #ifdef MACOSX 81 static const char* ENVVARNAME = "DYLD_LIBRARY_PATH"; 82 #else 83 static const char* ENVVARNAME = "LD_LIBRARY_PATH"; 84 #endif 85 char * libpath; 86 int freeLibpath; 87 88 char* value; 89 char* envstr; 90 int size; 91 92 size_t pathlen = strlen(path); 93 struct stat stat; 94 int ret; 95 char * unoinfo = malloc( 96 pathlen + RTL_CONSTASCII_LENGTH("/unoinfo") + 1); 97 /*TODO: overflow */ 98 if (unoinfo == NULL) { 99 fprintf(stderr, "Error: out of memory!\n"); 100 exit(EXIT_FAILURE); 101 } 102 strcpy(unoinfo, path); 103 strcpy( 104 unoinfo + pathlen, 105 "/unoinfo" + (pathlen == 0 || path[pathlen - 1] != '/' ? 0 : 1)); 106 ret = lstat(unoinfo, &stat); 107 free(unoinfo); 108 109 if (ret == 0) { 110 char * cmd = malloc( 111 2 * pathlen + RTL_CONSTASCII_LENGTH("/unoinfo c++") + 1); 112 /*TODO: overflow */ 113 char const * p; 114 char * q; 115 FILE * f; 116 size_t n = 1000; 117 size_t old = 0; 118 if (cmd == NULL) { 119 fprintf(stderr, "Error: out of memory!\n"); 120 exit(EXIT_FAILURE); 121 } 122 p = path; 123 q = cmd; 124 while (*p != '\0') { 125 *q++ = '\\'; 126 *q++ = *p++; 127 } 128 if (p == path || p[-1] != '/') { 129 *q++ = '/'; 130 } 131 strcpy(q, "unoinfo c++"); 132 f = popen(cmd, "r"); 133 free(cmd); 134 if (f == NULL) 135 { 136 fprintf(stderr, "Error: calling unoinfo failed!\n"); 137 exit(EXIT_FAILURE); 138 } 139 libpath = NULL; 140 for (;;) { 141 size_t m; 142 libpath = realloc(libpath, n); 143 if (libpath == NULL) { 144 fprintf( 145 stderr, 146 "Error: out of memory reading unoinfo output!\n"); 147 exit(EXIT_FAILURE); 148 } 149 m = fread(libpath + old, 1, n - old - 1, f); 150 if (m != n - old - 1) { 151 if (ferror(f)) { 152 fprintf(stderr, "Error: cannot read unoinfo output!\n"); 153 exit(EXIT_FAILURE); 154 } 155 libpath[old + m] = '\0'; 156 break; 157 } 158 if (n >= SAL_MAX_SIZE / 2) { 159 fprintf( 160 stderr, 161 "Error: out of memory reading unoinfo output!\n"); 162 exit(EXIT_FAILURE); 163 } 164 old = n - 1; 165 n *= 2; 166 } 167 if (pclose(f) != 0) { 168 fprintf(stderr, "Error: executing unoinfo failed!\n"); 169 exit(EXIT_FAILURE); 170 } 171 freeLibpath = 1; 172 } 173 else 174 { 175 /* Assume an old OOo 2.x installation without unoinfo: */ 176 libpath = (char *) path; 177 freeLibpath = 0; 178 } 179 180 value = getenv( ENVVARNAME ); 181 182 // workaround for finding wrong libsqlite3.dylib in the office installation 183 // For MacOS > 10.6 nss uses the system lib -> unresolved symbol _sqlite3_wal_checkpoint 184 #ifdef MACOSX 185 size = strlen( ENVVARNAME ) + strlen( "=/usr/lib:" ) + strlen( libpath ) + 1; 186 #else 187 size = strlen( ENVVARNAME ) + strlen( "=" ) + strlen( libpath ) + 1; 188 #endif 189 if ( value != NULL ) 190 size += strlen( PATHSEPARATOR ) + strlen( value ); 191 envstr = (char*) malloc( size ); 192 strcpy( envstr, ENVVARNAME ); 193 #ifdef MACOSX 194 strcat( envstr, "=/usr/lib:" ); 195 #else 196 strcat( envstr, "=" ); 197 #endif 198 strcat( envstr, libpath ); 199 if ( freeLibpath != 0 ) 200 { 201 free( libpath ); 202 } 203 if ( value != NULL ) 204 { 205 strcat( envstr, PATHSEPARATOR ); 206 strcat( envstr, value ); 207 } 208 putenv( envstr ); 209 #ifdef MACOSX 210 /* https://bz.apache.org/ooo/show_bug.cgi?id=127965 */ 211 value = getenv( "PATH" ); 212 size = strlen( "PATH" ) + strlen( "=/usr/local/bin" ); 213 if ( value != NULL ) 214 size += strlen( PATHSEPARATOR ) + strlen( value ); 215 envstr = (char*) malloc( size ); 216 strcpy( envstr, "PATH=" ); 217 if ( value != NULL ) { 218 strcat( envstr, value); 219 strcat( envstr, PATHSEPARATOR); 220 } 221 strcat( envstr, "/usr/local/bin" ); /* We are adding at the end */ 222 putenv( envstr ); 223 #endif 224 } 225 else 226 { 227 fprintf( stderr, "Warning: no office installation found!\n" ); 228 fflush( stderr ); 229 } 230 231 /* set the executable name for the application process */ 232 cmdname = createCommandName( argv[0] ); 233 argv[0] = cmdname; 234 235 /* 236 * create the application process; 237 * if successful, execvp doesn't return to the calling process 238 */ 239 execvp( cmdname, argv ); 240 fprintf( stderr, "Error: execvp failed!\n" ); 241 fflush( stderr ); 242 243 return 0; 244 } 245 246 /* 247 * Gets the path of a UNO installation. 248 * 249 * @return the installation path or NULL, if no installation was specified or 250 * found, or if an error occurred 251 */ 252 char const* getPath() 253 { 254 char const* path = cppuhelper_detail_findSofficePath(); 255 256 if ( path == NULL ) 257 { 258 fprintf( stderr, "Warning: getting path from PATH environment variable failed!\n" ); 259 fflush( stderr ); 260 } 261 262 return path; 263 } 264 265 /* 266 * Creates the application's executable file name. 267 * 268 * <p>The application's executable file name is the name of this executable 269 * prefixed by '_'.</p> 270 * 271 * @param argv0 specifies the argv[0] parameter of the main function 272 * 273 * @return the application's executable file name or NULL, if an error occurred 274 */ 275 char* createCommandName( char* argv0 ) 276 { 277 const char* CMDPREFIX = "_"; 278 const char* prgname = NULL; 279 280 char* cmdname = NULL; 281 char* sep = NULL; 282 Dl_info dl_info; 283 int pos; 284 285 /* get the executable file name from argv0 */ 286 prgname = argv0; 287 288 /* 289 * if argv0 doesn't contain an absolute path name, try to get the absolute 290 * path name from dladdr; note that this only works for Solaris, not for 291 * Linux 292 */ 293 if ( argv0 != NULL && *argv0 != SEPARATOR && 294 dladdr( (void*) &createCommandName, &dl_info ) && 295 dl_info.dli_fname != NULL && *dl_info.dli_fname == SEPARATOR ) 296 { 297 prgname = dl_info.dli_fname; 298 } 299 300 /* prefix the executable file name by '_' */ 301 if ( prgname != NULL ) 302 { 303 cmdname = (char*) malloc( strlen( prgname ) + strlen( CMDPREFIX ) + 1 ); 304 sep = strrchr( prgname, SEPARATOR ); 305 if ( sep != NULL ) 306 { 307 pos = ++sep - prgname; 308 strncpy( cmdname, prgname, pos ); 309 cmdname[ pos ] = '\0'; 310 strcat( cmdname, CMDPREFIX ); 311 strcat( cmdname, sep ); 312 } 313 else 314 { 315 strcpy( cmdname, CMDPREFIX ); 316 strcat( cmdname, prgname ); 317 } 318 } 319 320 return cmdname; 321 } 322