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