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