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