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