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 fprintf( stderr, "DYLD_LIBRARY_PATH=%s\n", envstr ); 210 211 } 212 else 213 { 214 fprintf( stderr, "Warning: no office installation found!\n" ); 215 fflush( stderr ); 216 } 217 218 /* set the executable name for the application process */ 219 cmdname = createCommandName( argv[0] ); 220 argv[0] = cmdname; 221 222 /* 223 * create the application process; 224 * if successful, execvp doesn't return to the calling process 225 */ 226 execvp( cmdname, argv ); 227 fprintf( stderr, "Error: execvp failed!\n" ); 228 fflush( stderr ); 229 230 return 0; 231 } 232 233 /* 234 * Gets the path of a UNO installation. 235 * 236 * @return the installation path or NULL, if no installation was specified or 237 * found, or if an error occured 238 */ 239 char const* getPath() 240 { 241 char const* path = cppuhelper_detail_findSofficePath(); 242 243 if ( path == NULL ) 244 { 245 fprintf( stderr, "Warning: getting path from PATH environment " 246 "variable failed!\n" ); 247 fflush( stderr ); 248 } 249 250 return path; 251 } 252 253 /* 254 * Creates the application's executable file name. 255 * 256 * <p>The application's executable file name is the name of this executable 257 * prefixed by '_'.</p> 258 * 259 * @param argv0 specifies the argv[0] parameter of the main function 260 * 261 * @return the application's executable file name or NULL, if an error occured 262 */ 263 char* createCommandName( char* argv0 ) 264 { 265 const char* CMDPREFIX = "_"; 266 const char* prgname = NULL; 267 268 char* cmdname = NULL; 269 char* sep = NULL; 270 Dl_info dl_info; 271 int pos; 272 273 /* get the executable file name from argv0 */ 274 prgname = argv0; 275 276 /* 277 * if argv0 doesn't contain an absolute path name, try to get the absolute 278 * path name from dladdr; note that this only works for Solaris, not for 279 * Linux 280 */ 281 if ( argv0 != NULL && *argv0 != SEPARATOR && 282 dladdr( (void*) &createCommandName, &dl_info ) && 283 dl_info.dli_fname != NULL && *dl_info.dli_fname == SEPARATOR ) 284 { 285 prgname = dl_info.dli_fname; 286 } 287 288 /* prefix the executable file name by '_' */ 289 if ( prgname != NULL ) 290 { 291 cmdname = (char*) malloc( strlen( prgname ) + strlen( CMDPREFIX ) + 1 ); 292 sep = strrchr( prgname, SEPARATOR ); 293 if ( sep != NULL ) 294 { 295 pos = ++sep - prgname; 296 strncpy( cmdname, prgname, pos ); 297 cmdname[ pos ] = '\0'; 298 strcat( cmdname, CMDPREFIX ); 299 strcat( cmdname, sep ); 300 } 301 else 302 { 303 strcpy( cmdname, CMDPREFIX ); 304 strcat( cmdname, prgname ); 305 } 306 } 307 308 return cmdname; 309 } 310