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 );
209*854bf195SJim Jagielski #ifdef MACOSX
2107d3beb53SJim Jagielski         /* https://bz.apache.org/ooo/show_bug.cgi?id=127965 */
2117d3beb53SJim Jagielski         value = getenv( "PATH" );
212*854bf195SJim 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*854bf195SJim Jagielski #endif
224cdf0e10cSrcweir     }
225cdf0e10cSrcweir     else
226cdf0e10cSrcweir     {
227bec0253dSJürgen Schmidt         fprintf( stderr, "Warning: no office installation found!\n" );
228cdf0e10cSrcweir         fflush( stderr );
229cdf0e10cSrcweir     }
230cdf0e10cSrcweir 
231cdf0e10cSrcweir     /* set the executable name for the application process */
232cdf0e10cSrcweir     cmdname = createCommandName( argv[0] );
233cdf0e10cSrcweir     argv[0] = cmdname;
234cdf0e10cSrcweir 
235cdf0e10cSrcweir     /*
236cdf0e10cSrcweir      * create the application process;
237cdf0e10cSrcweir      * if successful, execvp doesn't return to the calling process
238cdf0e10cSrcweir      */
239cdf0e10cSrcweir     execvp( cmdname, argv );
240cdf0e10cSrcweir     fprintf( stderr, "Error: execvp failed!\n" );
241cdf0e10cSrcweir     fflush( stderr );
242cdf0e10cSrcweir 
243cdf0e10cSrcweir     return 0;
244cdf0e10cSrcweir }
245cdf0e10cSrcweir 
246cdf0e10cSrcweir /*
247cdf0e10cSrcweir  * Gets the path of a UNO installation.
248cdf0e10cSrcweir  *
249cdf0e10cSrcweir  * @return the installation path or NULL, if no installation was specified or
250a893be29SPedro Giffuni  *         found, or if an error occurred
251cdf0e10cSrcweir  */
252cdf0e10cSrcweir char const* getPath()
253cdf0e10cSrcweir {
254cdf0e10cSrcweir     char const* path = cppuhelper_detail_findSofficePath();
255cdf0e10cSrcweir 
256cdf0e10cSrcweir     if ( path == NULL )
257cdf0e10cSrcweir     {
2582e9bc605SJürgen Schmidt         fprintf( stderr, "Warning: getting path from PATH environment variable failed!\n" );
259cdf0e10cSrcweir         fflush( stderr );
260cdf0e10cSrcweir     }
261cdf0e10cSrcweir 
262cdf0e10cSrcweir     return path;
263cdf0e10cSrcweir }
264cdf0e10cSrcweir 
265cdf0e10cSrcweir /*
266cdf0e10cSrcweir  * Creates the application's executable file name.
267cdf0e10cSrcweir  *
268cdf0e10cSrcweir  * <p>The application's executable file name is the name of this executable
269cdf0e10cSrcweir  * prefixed by '_'.</p>
270cdf0e10cSrcweir  *
271cdf0e10cSrcweir  * @param argv0 specifies the argv[0] parameter of the main function
272cdf0e10cSrcweir  *
273a893be29SPedro Giffuni  * @return the application's executable file name or NULL, if an error occurred
274cdf0e10cSrcweir  */
275cdf0e10cSrcweir char* createCommandName( char* argv0 )
276cdf0e10cSrcweir {
277cdf0e10cSrcweir     const char* CMDPREFIX = "_";
278cdf0e10cSrcweir     const char* prgname = NULL;
279cdf0e10cSrcweir 
280cdf0e10cSrcweir     char* cmdname = NULL;
281cdf0e10cSrcweir     char* sep = NULL;
282cdf0e10cSrcweir     Dl_info dl_info;
283cdf0e10cSrcweir     int pos;
284cdf0e10cSrcweir 
285cdf0e10cSrcweir     /* get the executable file name from argv0 */
286cdf0e10cSrcweir 	prgname = argv0;
287cdf0e10cSrcweir 
288cdf0e10cSrcweir 	/*
289cdf0e10cSrcweir      * if argv0 doesn't contain an absolute path name, try to get the absolute
290cdf0e10cSrcweir      * path name from dladdr; note that this only works for Solaris, not for
291cdf0e10cSrcweir      * Linux
292cdf0e10cSrcweir      */
293cdf0e10cSrcweir     if ( argv0 != NULL && *argv0 != SEPARATOR &&
294cdf0e10cSrcweir          dladdr( (void*) &createCommandName, &dl_info ) &&
295cdf0e10cSrcweir          dl_info.dli_fname != NULL && *dl_info.dli_fname == SEPARATOR )
296cdf0e10cSrcweir     {
297cdf0e10cSrcweir         prgname = dl_info.dli_fname;
298cdf0e10cSrcweir 	}
299cdf0e10cSrcweir 
300cdf0e10cSrcweir     /* prefix the executable file name by '_' */
301cdf0e10cSrcweir     if ( prgname != NULL )
302cdf0e10cSrcweir 	{
303cdf0e10cSrcweir         cmdname = (char*) malloc( strlen( prgname ) + strlen( CMDPREFIX ) + 1 );
304cdf0e10cSrcweir         sep = strrchr( prgname, SEPARATOR );
305cdf0e10cSrcweir         if ( sep != NULL )
306cdf0e10cSrcweir         {
307cdf0e10cSrcweir 			pos = ++sep - prgname;
308cdf0e10cSrcweir             strncpy( cmdname, prgname, pos );
309cdf0e10cSrcweir             cmdname[ pos ] = '\0';
310cdf0e10cSrcweir             strcat( cmdname, CMDPREFIX );
311cdf0e10cSrcweir             strcat( cmdname, sep );
312cdf0e10cSrcweir         }
313cdf0e10cSrcweir         else
314cdf0e10cSrcweir 		{
315cdf0e10cSrcweir             strcpy( cmdname, CMDPREFIX );
316cdf0e10cSrcweir 			strcat( cmdname, prgname );
317cdf0e10cSrcweir 		}
318cdf0e10cSrcweir 	}
319cdf0e10cSrcweir 
320cdf0e10cSrcweir     return cmdname;
321cdf0e10cSrcweir }
322