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