1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir #include <stdlib.h>
29*cdf0e10cSrcweir #include <unistd.h>
30*cdf0e10cSrcweir #include <stdio.h>
31*cdf0e10cSrcweir #include <string.h>
32*cdf0e10cSrcweir #include <sys/stat.h>
33*cdf0e10cSrcweir 
34*cdf0e10cSrcweir #ifdef LINUX
35*cdf0e10cSrcweir #define __USE_GNU
36*cdf0e10cSrcweir #endif
37*cdf0e10cSrcweir #include <dlfcn.h>
38*cdf0e10cSrcweir 
39*cdf0e10cSrcweir #include "cppuhelper/findsofficepath.h"
40*cdf0e10cSrcweir #include "rtl/string.h"
41*cdf0e10cSrcweir #include "sal/types.h"
42*cdf0e10cSrcweir 
43*cdf0e10cSrcweir char const* getPath();
44*cdf0e10cSrcweir char* createCommandName( char* argv0 );
45*cdf0e10cSrcweir 
46*cdf0e10cSrcweir const int SEPARATOR = '/';
47*cdf0e10cSrcweir const char* PATHSEPARATOR = ":";
48*cdf0e10cSrcweir 
49*cdf0e10cSrcweir 
50*cdf0e10cSrcweir /*
51*cdf0e10cSrcweir  * The main function implements a loader for applications which use UNO.
52*cdf0e10cSrcweir  *
53*cdf0e10cSrcweir  * <p>This code runs on the Unix/Linux platforms only.</p>
54*cdf0e10cSrcweir  *
55*cdf0e10cSrcweir  * <p>The main function detects a UNO installation on the system and adds the
56*cdf0e10cSrcweir  * relevant directories of the installation to the LD_LIBRARY_PATH environment
57*cdf0e10cSrcweir  * variable. After that, the application process is loaded and started, whereby
58*cdf0e10cSrcweir  * the new process inherits the environment of the calling process, including
59*cdf0e10cSrcweir  * the modified LD_LIBRARY_PATH environment variable. The application's
60*cdf0e10cSrcweir  * executable name must be the same as the name of this executable, prefixed
61*cdf0e10cSrcweir  * by '_'.</p>
62*cdf0e10cSrcweir  * <p>On MACOSX DYLD_LIBRARY_PATH is used instead of LD_LIBRARY_PATH!<p>
63*cdf0e10cSrcweir  *
64*cdf0e10cSrcweir  * <p>A UNO installation can be specified by the user by setting the UNO_PATH
65*cdf0e10cSrcweir  * environment variable to the program directory of the UNO installation.
66*cdf0e10cSrcweir  * If no installation is specified by the user, the default installation on
67*cdf0e10cSrcweir  * the system will be taken. The default installation is found from the
68*cdf0e10cSrcweir  * PATH environment variable. This requires that the 'soffice' executable or
69*cdf0e10cSrcweir  * a symbolic link is in one of the directories listed in the PATH environment
70*cdf0e10cSrcweir  * variable.</p>
71*cdf0e10cSrcweir  */
72*cdf0e10cSrcweir int main( int argc, char *argv[] )
73*cdf0e10cSrcweir {
74*cdf0e10cSrcweir     char const* path;
75*cdf0e10cSrcweir     char* cmdname;
76*cdf0e10cSrcweir 
77*cdf0e10cSrcweir     (void) argc; /* avoid warning about unused parameter */
78*cdf0e10cSrcweir 
79*cdf0e10cSrcweir     /* get the path of the UNO installation */
80*cdf0e10cSrcweir     path = getPath();
81*cdf0e10cSrcweir 
82*cdf0e10cSrcweir     if ( path != NULL )
83*cdf0e10cSrcweir     {
84*cdf0e10cSrcweir #ifdef MACOSX
85*cdf0e10cSrcweir         static const char* ENVVARNAME = "DYLD_LIBRARY_PATH";
86*cdf0e10cSrcweir #else
87*cdf0e10cSrcweir         static const char* ENVVARNAME = "LD_LIBRARY_PATH";
88*cdf0e10cSrcweir #endif
89*cdf0e10cSrcweir         char * libpath;
90*cdf0e10cSrcweir         int freeLibpath;
91*cdf0e10cSrcweir 
92*cdf0e10cSrcweir         char* value;
93*cdf0e10cSrcweir         char* envstr;
94*cdf0e10cSrcweir         int size;
95*cdf0e10cSrcweir 
96*cdf0e10cSrcweir         size_t pathlen = strlen(path);
97*cdf0e10cSrcweir         struct stat stat;
98*cdf0e10cSrcweir         int ret;
99*cdf0e10cSrcweir         char * unoinfo = malloc(
100*cdf0e10cSrcweir             pathlen + RTL_CONSTASCII_LENGTH("/unoinfo") + 1);
101*cdf0e10cSrcweir             /*TODO: overflow */
102*cdf0e10cSrcweir         if (unoinfo == NULL) {
103*cdf0e10cSrcweir             fprintf(stderr, "Error: out of memory!\n");
104*cdf0e10cSrcweir             exit(EXIT_FAILURE);
105*cdf0e10cSrcweir         }
106*cdf0e10cSrcweir         strcpy(unoinfo, path);
107*cdf0e10cSrcweir         strcpy(
108*cdf0e10cSrcweir             unoinfo + pathlen,
109*cdf0e10cSrcweir             "/unoinfo" + (pathlen == 0 || path[pathlen - 1] != '/' ? 0 : 1));
110*cdf0e10cSrcweir         ret = lstat(unoinfo, &stat);
111*cdf0e10cSrcweir         free(unoinfo);
112*cdf0e10cSrcweir 
113*cdf0e10cSrcweir         if (ret == 0) {
114*cdf0e10cSrcweir             char * cmd = malloc(
115*cdf0e10cSrcweir                 2 * pathlen + RTL_CONSTASCII_LENGTH("/unoinfo c++") + 1);
116*cdf0e10cSrcweir                 /*TODO: overflow */
117*cdf0e10cSrcweir             char const * p;
118*cdf0e10cSrcweir             char * q;
119*cdf0e10cSrcweir             FILE * f;
120*cdf0e10cSrcweir             size_t n = 1000;
121*cdf0e10cSrcweir             size_t old = 0;
122*cdf0e10cSrcweir             if (cmd == NULL) {
123*cdf0e10cSrcweir                 fprintf(stderr, "Error: out of memory!\n");
124*cdf0e10cSrcweir                 exit(EXIT_FAILURE);
125*cdf0e10cSrcweir             }
126*cdf0e10cSrcweir             p = path;
127*cdf0e10cSrcweir             q = cmd;
128*cdf0e10cSrcweir             while (*p != '\0') {
129*cdf0e10cSrcweir                 *q++ = '\\';
130*cdf0e10cSrcweir                 *q++ = *p++;
131*cdf0e10cSrcweir             }
132*cdf0e10cSrcweir             if (p == path || p[-1] != '/') {
133*cdf0e10cSrcweir                 *q++ = '/';
134*cdf0e10cSrcweir             }
135*cdf0e10cSrcweir             strcpy(q, "unoinfo c++");
136*cdf0e10cSrcweir             f = popen(cmd, "r");
137*cdf0e10cSrcweir             free(cmd);
138*cdf0e10cSrcweir             if (f == NULL)
139*cdf0e10cSrcweir             {
140*cdf0e10cSrcweir                 fprintf(stderr, "Error: calling unoinfo failed!\n");
141*cdf0e10cSrcweir                 exit(EXIT_FAILURE);
142*cdf0e10cSrcweir             }
143*cdf0e10cSrcweir             libpath = NULL;
144*cdf0e10cSrcweir             for (;;) {
145*cdf0e10cSrcweir                 size_t m;
146*cdf0e10cSrcweir                 libpath = realloc(libpath, n);
147*cdf0e10cSrcweir                 if (libpath == NULL) {
148*cdf0e10cSrcweir                     fprintf(
149*cdf0e10cSrcweir                         stderr,
150*cdf0e10cSrcweir                         "Error: out of memory reading unoinfo output!\n");
151*cdf0e10cSrcweir                     exit(EXIT_FAILURE);
152*cdf0e10cSrcweir                 }
153*cdf0e10cSrcweir                 m = fread(libpath + old, 1, n - old - 1, f);
154*cdf0e10cSrcweir                 if (m != n - old - 1) {
155*cdf0e10cSrcweir                     if (ferror(f)) {
156*cdf0e10cSrcweir                         fprintf(stderr, "Error: cannot read unoinfo output!\n");
157*cdf0e10cSrcweir                         exit(EXIT_FAILURE);
158*cdf0e10cSrcweir                     }
159*cdf0e10cSrcweir                     libpath[old + m] = '\0';
160*cdf0e10cSrcweir                     break;
161*cdf0e10cSrcweir                 }
162*cdf0e10cSrcweir                 if (n >= SAL_MAX_SIZE / 2) {
163*cdf0e10cSrcweir                     fprintf(
164*cdf0e10cSrcweir                         stderr,
165*cdf0e10cSrcweir                         "Error: out of memory reading unoinfo output!\n");
166*cdf0e10cSrcweir                     exit(EXIT_FAILURE);
167*cdf0e10cSrcweir                 }
168*cdf0e10cSrcweir                 old = n - 1;
169*cdf0e10cSrcweir                 n *= 2;
170*cdf0e10cSrcweir             }
171*cdf0e10cSrcweir             if (pclose(f) != 0) {
172*cdf0e10cSrcweir                 fprintf(stderr, "Error: executing unoinfo failed!\n");
173*cdf0e10cSrcweir                 exit(EXIT_FAILURE);
174*cdf0e10cSrcweir             }
175*cdf0e10cSrcweir             freeLibpath = 1;
176*cdf0e10cSrcweir         }
177*cdf0e10cSrcweir         else
178*cdf0e10cSrcweir         {
179*cdf0e10cSrcweir             /* Assume an old OOo 2.x installation without unoinfo: */
180*cdf0e10cSrcweir             libpath = (char *) path;
181*cdf0e10cSrcweir             freeLibpath = 0;
182*cdf0e10cSrcweir         }
183*cdf0e10cSrcweir 
184*cdf0e10cSrcweir         value = getenv( ENVVARNAME );
185*cdf0e10cSrcweir 
186*cdf0e10cSrcweir         size = strlen( ENVVARNAME ) + strlen( "=" ) + strlen( libpath ) + 1;
187*cdf0e10cSrcweir 		if ( value != NULL )
188*cdf0e10cSrcweir             size += strlen( PATHSEPARATOR ) + strlen( value );
189*cdf0e10cSrcweir 		envstr = (char*) malloc( size );
190*cdf0e10cSrcweir         strcpy( envstr, ENVVARNAME );
191*cdf0e10cSrcweir         strcat( envstr, "=" );
192*cdf0e10cSrcweir         strcat( envstr, libpath );
193*cdf0e10cSrcweir         if ( freeLibpath != 0 )
194*cdf0e10cSrcweir         {
195*cdf0e10cSrcweir             free( libpath );
196*cdf0e10cSrcweir         }
197*cdf0e10cSrcweir 		if ( value != NULL )
198*cdf0e10cSrcweir 		{
199*cdf0e10cSrcweir             strcat( envstr, PATHSEPARATOR );
200*cdf0e10cSrcweir             strcat( envstr, value );
201*cdf0e10cSrcweir 		}
202*cdf0e10cSrcweir         putenv( envstr );
203*cdf0e10cSrcweir     }
204*cdf0e10cSrcweir     else
205*cdf0e10cSrcweir     {
206*cdf0e10cSrcweir         fprintf( stderr, "Warning: no UNO installation found!\n" );
207*cdf0e10cSrcweir         fflush( stderr );
208*cdf0e10cSrcweir     }
209*cdf0e10cSrcweir 
210*cdf0e10cSrcweir     /* set the executable name for the application process */
211*cdf0e10cSrcweir     cmdname = createCommandName( argv[0] );
212*cdf0e10cSrcweir     argv[0] = cmdname;
213*cdf0e10cSrcweir 
214*cdf0e10cSrcweir     /*
215*cdf0e10cSrcweir      * create the application process;
216*cdf0e10cSrcweir      * if successful, execvp doesn't return to the calling process
217*cdf0e10cSrcweir      */
218*cdf0e10cSrcweir     execvp( cmdname, argv );
219*cdf0e10cSrcweir     fprintf( stderr, "Error: execvp failed!\n" );
220*cdf0e10cSrcweir     fflush( stderr );
221*cdf0e10cSrcweir 
222*cdf0e10cSrcweir     return 0;
223*cdf0e10cSrcweir }
224*cdf0e10cSrcweir 
225*cdf0e10cSrcweir /*
226*cdf0e10cSrcweir  * Gets the path of a UNO installation.
227*cdf0e10cSrcweir  *
228*cdf0e10cSrcweir  * @return the installation path or NULL, if no installation was specified or
229*cdf0e10cSrcweir  *         found, or if an error occured
230*cdf0e10cSrcweir  */
231*cdf0e10cSrcweir char const* getPath()
232*cdf0e10cSrcweir {
233*cdf0e10cSrcweir     char const* path = cppuhelper_detail_findSofficePath();
234*cdf0e10cSrcweir 
235*cdf0e10cSrcweir     if ( path == NULL )
236*cdf0e10cSrcweir     {
237*cdf0e10cSrcweir         fprintf( stderr, "Warning: getting path from PATH environment "
238*cdf0e10cSrcweir                  "variable failed!\n" );
239*cdf0e10cSrcweir         fflush( stderr );
240*cdf0e10cSrcweir     }
241*cdf0e10cSrcweir 
242*cdf0e10cSrcweir     return path;
243*cdf0e10cSrcweir }
244*cdf0e10cSrcweir 
245*cdf0e10cSrcweir /*
246*cdf0e10cSrcweir  * Creates the application's executable file name.
247*cdf0e10cSrcweir  *
248*cdf0e10cSrcweir  * <p>The application's executable file name is the name of this executable
249*cdf0e10cSrcweir  * prefixed by '_'.</p>
250*cdf0e10cSrcweir  *
251*cdf0e10cSrcweir  * @param argv0 specifies the argv[0] parameter of the main function
252*cdf0e10cSrcweir  *
253*cdf0e10cSrcweir  * @return the application's executable file name or NULL, if an error occured
254*cdf0e10cSrcweir  */
255*cdf0e10cSrcweir char* createCommandName( char* argv0 )
256*cdf0e10cSrcweir {
257*cdf0e10cSrcweir     const char* CMDPREFIX = "_";
258*cdf0e10cSrcweir     const char* prgname = NULL;
259*cdf0e10cSrcweir 
260*cdf0e10cSrcweir     char* cmdname = NULL;
261*cdf0e10cSrcweir     char* sep = NULL;
262*cdf0e10cSrcweir     Dl_info dl_info;
263*cdf0e10cSrcweir     int pos;
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir     /* get the executable file name from argv0 */
266*cdf0e10cSrcweir 	prgname = argv0;
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir 	/*
269*cdf0e10cSrcweir      * if argv0 doesn't contain an absolute path name, try to get the absolute
270*cdf0e10cSrcweir      * path name from dladdr; note that this only works for Solaris, not for
271*cdf0e10cSrcweir      * Linux
272*cdf0e10cSrcweir      */
273*cdf0e10cSrcweir     if ( argv0 != NULL && *argv0 != SEPARATOR &&
274*cdf0e10cSrcweir          dladdr( (void*) &createCommandName, &dl_info ) &&
275*cdf0e10cSrcweir          dl_info.dli_fname != NULL && *dl_info.dli_fname == SEPARATOR )
276*cdf0e10cSrcweir     {
277*cdf0e10cSrcweir         prgname = dl_info.dli_fname;
278*cdf0e10cSrcweir 	}
279*cdf0e10cSrcweir 
280*cdf0e10cSrcweir     /* prefix the executable file name by '_' */
281*cdf0e10cSrcweir     if ( prgname != NULL )
282*cdf0e10cSrcweir 	{
283*cdf0e10cSrcweir         cmdname = (char*) malloc( strlen( prgname ) + strlen( CMDPREFIX ) + 1 );
284*cdf0e10cSrcweir         sep = strrchr( prgname, SEPARATOR );
285*cdf0e10cSrcweir         if ( sep != NULL )
286*cdf0e10cSrcweir         {
287*cdf0e10cSrcweir 			pos = ++sep - prgname;
288*cdf0e10cSrcweir             strncpy( cmdname, prgname, pos );
289*cdf0e10cSrcweir             cmdname[ pos ] = '\0';
290*cdf0e10cSrcweir             strcat( cmdname, CMDPREFIX );
291*cdf0e10cSrcweir             strcat( cmdname, sep );
292*cdf0e10cSrcweir         }
293*cdf0e10cSrcweir         else
294*cdf0e10cSrcweir 		{
295*cdf0e10cSrcweir             strcpy( cmdname, CMDPREFIX );
296*cdf0e10cSrcweir 			strcat( cmdname, prgname );
297*cdf0e10cSrcweir 		}
298*cdf0e10cSrcweir 	}
299*cdf0e10cSrcweir 
300*cdf0e10cSrcweir     return cmdname;
301*cdf0e10cSrcweir }
302