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 */
main(int argc,char * argv[])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 if (!strstr ( value, "/usr/local/bin" )) {
213 size = strlen( "PATH" ) + strlen( "=/usr/local/bin" ) + 1;
214 if ( value != NULL )
215 size += strlen( PATHSEPARATOR ) + strlen( value );
216 envstr = (char*) malloc( size );
217 strcpy( envstr, "PATH=" );
218 if ( value != NULL ) {
219 strcat( envstr, value);
220 strcat( envstr, PATHSEPARATOR);
221 }
222 strcat( envstr, "/usr/local/bin" ); /* We are adding at the end */
223 putenv( envstr );
224 }
225
226 /* https://bz.apache.org/ooo/show_bug.cgi?id=127966 */
227 value = getenv ( "HOME" );
228 if ( value && *value ) {
229 chdir ( value );
230 } else {
231 chdir ( "/tmp" );
232 }
233 #endif
234 }
235 else
236 {
237 fprintf( stderr, "Warning: no office installation found!\n" );
238 fflush( stderr );
239 }
240
241 /* set the executable name for the application process */
242 cmdname = createCommandName( argv[0] );
243 argv[0] = cmdname;
244
245 /*
246 * create the application process;
247 * if successful, execvp doesn't return to the calling process
248 */
249 execvp( cmdname, argv );
250 fprintf( stderr, "Error: execvp failed!\n" );
251 fflush( stderr );
252
253 return 0;
254 }
255
256 /*
257 * Gets the path of a UNO installation.
258 *
259 * @return the installation path or NULL, if no installation was specified or
260 * found, or if an error occured
261 */
getPath()262 char const* getPath()
263 {
264 char const* path = cppuhelper_detail_findSofficePath();
265
266 if ( path == NULL )
267 {
268 fprintf( stderr, "Warning: getting path from PATH environment variable failed!\n" );
269 fflush( stderr );
270 }
271
272 return path;
273 }
274
275 /*
276 * Creates the application's executable file name.
277 *
278 * <p>The application's executable file name is the name of this executable
279 * prefixed by '_'.</p>
280 *
281 * @param argv0 specifies the argv[0] parameter of the main function
282 *
283 * @return the application's executable file name or NULL, if an error occured
284 */
createCommandName(char * argv0)285 char* createCommandName( char* argv0 )
286 {
287 const char* CMDPREFIX = "_";
288 const char* prgname = NULL;
289
290 char* cmdname = NULL;
291 char* sep = NULL;
292 Dl_info dl_info;
293 int pos;
294
295 /* get the executable file name from argv0 */
296 prgname = argv0;
297
298 /*
299 * if argv0 doesn't contain an absolute path name, try to get the absolute
300 * path name from dladdr; note that this only works for Solaris, not for
301 * Linux
302 */
303 if ( argv0 != NULL && *argv0 != SEPARATOR &&
304 dladdr( (void*) &createCommandName, &dl_info ) &&
305 dl_info.dli_fname != NULL && *dl_info.dli_fname == SEPARATOR )
306 {
307 prgname = dl_info.dli_fname;
308 }
309
310 /* prefix the executable file name by '_' */
311 if ( prgname != NULL )
312 {
313 cmdname = (char*) malloc( strlen( prgname ) + strlen( CMDPREFIX ) + 1 );
314 sep = strrchr( prgname, SEPARATOR );
315 if ( sep != NULL )
316 {
317 pos = ++sep - prgname;
318 strncpy( cmdname, prgname, pos );
319 cmdname[ pos ] = '\0';
320 strcat( cmdname, CMDPREFIX );
321 strcat( cmdname, sep );
322 }
323 else
324 {
325 strcpy( cmdname, CMDPREFIX );
326 strcat( cmdname, prgname );
327 }
328 }
329
330 return cmdname;
331 }
332