~ldgoodridge95/ubuntu/vivid/upstart/rm-libjson0-dev

« back to all changes in this revision

Viewing changes to intl/relocatable.c

Tags: upstream-1.7
ImportĀ upstreamĀ versionĀ 1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Provide relocatable packages.
 
2
   Copyright (C) 2003-2006 Free Software Foundation, Inc.
 
3
   Written by Bruno Haible <bruno@clisp.org>, 2003.
 
4
 
 
5
   This program is free software; you can redistribute it and/or modify it
 
6
   under the terms of the GNU Library General Public License as published
 
7
   by the Free Software Foundation; either version 2, or (at your option)
 
8
   any later version.
 
9
 
 
10
   This program is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
   Library General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU Library General Public
 
16
   License along with this program; if not, write to the Free Software
 
17
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
 
18
   USA.  */
 
19
 
 
20
 
 
21
/* Tell glibc's <stdio.h> to provide a prototype for getline().
 
22
   This must come before <config.h> because <config.h> may include
 
23
   <features.h>, and once <features.h> has been included, it's too late.  */
 
24
#ifndef _GNU_SOURCE
 
25
# define _GNU_SOURCE    1
 
26
#endif
 
27
 
 
28
#include <config.h>
 
29
 
 
30
/* Specification.  */
 
31
#include "relocatable.h"
 
32
 
 
33
#if ENABLE_RELOCATABLE
 
34
 
 
35
#include <stddef.h>
 
36
#include <stdio.h>
 
37
#include <stdlib.h>
 
38
#include <string.h>
 
39
 
 
40
#ifdef NO_XMALLOC
 
41
# define xmalloc malloc
 
42
#else
 
43
# include "xalloc.h"
 
44
#endif
 
45
 
 
46
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__
 
47
# define WIN32_LEAN_AND_MEAN
 
48
# include <windows.h>
 
49
#endif
 
50
 
 
51
#if DEPENDS_ON_LIBCHARSET
 
52
# include <libcharset.h>
 
53
#endif
 
54
#if DEPENDS_ON_LIBICONV && HAVE_ICONV
 
55
# include <iconv.h>
 
56
#endif
 
57
#if DEPENDS_ON_LIBINTL && ENABLE_NLS
 
58
# include <libintl.h>
 
59
#endif
 
60
 
 
61
/* Faked cheap 'bool'.  */
 
62
#undef bool
 
63
#undef false
 
64
#undef true
 
65
#define bool int
 
66
#define false 0
 
67
#define true 1
 
68
 
 
69
/* Pathname support.
 
70
   ISSLASH(C)           tests whether C is a directory separator character.
 
71
   IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
 
72
 */
 
73
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
 
74
  /* Win32, Cygwin, OS/2, DOS */
 
75
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
 
76
# define HAS_DEVICE(P) \
 
77
    ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
 
78
     && (P)[1] == ':')
 
79
# define IS_PATH_WITH_DIR(P) \
 
80
    (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
 
81
# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
 
82
#else
 
83
  /* Unix */
 
84
# define ISSLASH(C) ((C) == '/')
 
85
# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
 
86
# define FILE_SYSTEM_PREFIX_LEN(P) 0
 
87
#endif
 
88
 
 
89
/* Original installation prefix.  */
 
90
static char *orig_prefix;
 
91
static size_t orig_prefix_len;
 
92
/* Current installation prefix.  */
 
93
static char *curr_prefix;
 
94
static size_t curr_prefix_len;
 
95
/* These prefixes do not end in a slash.  Anything that will be concatenated
 
96
   to them must start with a slash.  */
 
97
 
 
98
/* Sets the original and the current installation prefix of this module.
 
99
   Relocation simply replaces a pathname starting with the original prefix
 
100
   by the corresponding pathname with the current prefix instead.  Both
 
101
   prefixes should be directory names without trailing slash (i.e. use ""
 
102
   instead of "/").  */
 
103
static void
 
104
set_this_relocation_prefix (const char *orig_prefix_arg,
 
105
                            const char *curr_prefix_arg)
 
106
{
 
107
  if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
 
108
      /* Optimization: if orig_prefix and curr_prefix are equal, the
 
109
         relocation is a nop.  */
 
110
      && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
 
111
    {
 
112
      /* Duplicate the argument strings.  */
 
113
      char *memory;
 
114
 
 
115
      orig_prefix_len = strlen (orig_prefix_arg);
 
116
      curr_prefix_len = strlen (curr_prefix_arg);
 
117
      memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
 
118
#ifdef NO_XMALLOC
 
119
      if (memory != NULL)
 
120
#endif
 
121
        {
 
122
          memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
 
123
          orig_prefix = memory;
 
124
          memory += orig_prefix_len + 1;
 
125
          memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
 
126
          curr_prefix = memory;
 
127
          return;
 
128
        }
 
129
    }
 
130
  orig_prefix = NULL;
 
131
  curr_prefix = NULL;
 
132
  /* Don't worry about wasted memory here - this function is usually only
 
133
     called once.  */
 
134
}
 
135
 
 
136
/* Sets the original and the current installation prefix of the package.
 
137
   Relocation simply replaces a pathname starting with the original prefix
 
138
   by the corresponding pathname with the current prefix instead.  Both
 
139
   prefixes should be directory names without trailing slash (i.e. use ""
 
140
   instead of "/").  */
 
141
void
 
142
set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
 
143
{
 
144
  set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
 
145
 
 
146
  /* Now notify all dependent libraries.  */
 
147
#if DEPENDS_ON_LIBCHARSET
 
148
  libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
 
149
#endif
 
150
#if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
 
151
  libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
 
152
#endif
 
153
#if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
 
154
  libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
 
155
#endif
 
156
}
 
157
 
 
158
#if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
 
159
 
 
160
/* Convenience function:
 
161
   Computes the current installation prefix, based on the original
 
162
   installation prefix, the original installation directory of a particular
 
163
   file, and the current pathname of this file.  Returns NULL upon failure.  */
 
164
#ifdef IN_LIBRARY
 
165
#define compute_curr_prefix local_compute_curr_prefix
 
166
static
 
167
#endif
 
168
const char *
 
169
compute_curr_prefix (const char *orig_installprefix,
 
170
                     const char *orig_installdir,
 
171
                     const char *curr_pathname)
 
172
{
 
173
  const char *curr_installdir;
 
174
  const char *rel_installdir;
 
175
 
 
176
  if (curr_pathname == NULL)
 
177
    return NULL;
 
178
 
 
179
  /* Determine the relative installation directory, relative to the prefix.
 
180
     This is simply the difference between orig_installprefix and
 
181
     orig_installdir.  */
 
182
  if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
 
183
      != 0)
 
184
    /* Shouldn't happen - nothing should be installed outside $(prefix).  */
 
185
    return NULL;
 
186
  rel_installdir = orig_installdir + strlen (orig_installprefix);
 
187
 
 
188
  /* Determine the current installation directory.  */
 
189
  {
 
190
    const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
 
191
    const char *p = curr_pathname + strlen (curr_pathname);
 
192
    char *q;
 
193
 
 
194
    while (p > p_base)
 
195
      {
 
196
        p--;
 
197
        if (ISSLASH (*p))
 
198
          break;
 
199
      }
 
200
 
 
201
    q = (char *) xmalloc (p - curr_pathname + 1);
 
202
#ifdef NO_XMALLOC
 
203
    if (q == NULL)
 
204
      return NULL;
 
205
#endif
 
206
    memcpy (q, curr_pathname, p - curr_pathname);
 
207
    q[p - curr_pathname] = '\0';
 
208
    curr_installdir = q;
 
209
  }
 
210
 
 
211
  /* Compute the current installation prefix by removing the trailing
 
212
     rel_installdir from it.  */
 
213
  {
 
214
    const char *rp = rel_installdir + strlen (rel_installdir);
 
215
    const char *cp = curr_installdir + strlen (curr_installdir);
 
216
    const char *cp_base =
 
217
      curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
 
218
 
 
219
    while (rp > rel_installdir && cp > cp_base)
 
220
      {
 
221
        bool same = false;
 
222
        const char *rpi = rp;
 
223
        const char *cpi = cp;
 
224
 
 
225
        while (rpi > rel_installdir && cpi > cp_base)
 
226
          {
 
227
            rpi--;
 
228
            cpi--;
 
229
            if (ISSLASH (*rpi) || ISSLASH (*cpi))
 
230
              {
 
231
                if (ISSLASH (*rpi) && ISSLASH (*cpi))
 
232
                  same = true;
 
233
                break;
 
234
              }
 
235
            /* Do case-insensitive comparison if the filesystem is always or
 
236
               often case-insensitive.  It's better to accept the comparison
 
237
               if the difference is only in case, rather than to fail.  */
 
238
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
 
239
            /* Win32, Cygwin, OS/2, DOS - case insignificant filesystem */
 
240
            if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
 
241
                != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
 
242
              break;
 
243
#else
 
244
            if (*rpi != *cpi)
 
245
              break;
 
246
#endif
 
247
          }
 
248
        if (!same)
 
249
          break;
 
250
        /* The last pathname component was the same.  opi and cpi now point
 
251
           to the slash before it.  */
 
252
        rp = rpi;
 
253
        cp = cpi;
 
254
      }
 
255
 
 
256
    if (rp > rel_installdir)
 
257
      /* Unexpected: The curr_installdir does not end with rel_installdir.  */
 
258
      return NULL;
 
259
 
 
260
    {
 
261
      size_t curr_prefix_len = cp - curr_installdir;
 
262
      char *curr_prefix;
 
263
 
 
264
      curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
 
265
#ifdef NO_XMALLOC
 
266
      if (curr_prefix == NULL)
 
267
        return NULL;
 
268
#endif
 
269
      memcpy (curr_prefix, curr_installdir, curr_prefix_len);
 
270
      curr_prefix[curr_prefix_len] = '\0';
 
271
 
 
272
      return curr_prefix;
 
273
    }
 
274
  }
 
275
}
 
276
 
 
277
#endif /* !IN_LIBRARY || PIC */
 
278
 
 
279
#if defined PIC && defined INSTALLDIR
 
280
 
 
281
/* Full pathname of shared library, or NULL.  */
 
282
static char *shared_library_fullname;
 
283
 
 
284
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__
 
285
 
 
286
/* Determine the full pathname of the shared library when it is loaded.  */
 
287
 
 
288
BOOL WINAPI
 
289
DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
 
290
{
 
291
  (void) reserved;
 
292
 
 
293
  if (event == DLL_PROCESS_ATTACH)
 
294
    {
 
295
      /* The DLL is being loaded into an application's address range.  */
 
296
      static char location[MAX_PATH];
 
297
 
 
298
      if (!GetModuleFileName (module_handle, location, sizeof (location)))
 
299
        /* Shouldn't happen.  */
 
300
        return FALSE;
 
301
 
 
302
      if (!IS_PATH_WITH_DIR (location))
 
303
        /* Shouldn't happen.  */
 
304
        return FALSE;
 
305
 
 
306
      {
 
307
#if defined __CYGWIN__
 
308
        /* On Cygwin, we need to convert paths coming from Win32 system calls
 
309
           to the Unix-like slashified notation.  */
 
310
        static char location_as_posix_path[2 * MAX_PATH];
 
311
        /* There's no error return defined for cygwin_conv_to_posix_path.
 
312
           See cygwin-api/func-cygwin-conv-to-posix-path.html.
 
313
           Does it overflow the buffer of expected size MAX_PATH or does it
 
314
           truncate the path?  I don't know.  Let's catch both.  */
 
315
        cygwin_conv_to_posix_path (location, location_as_posix_path);
 
316
        location_as_posix_path[MAX_PATH - 1] = '\0';
 
317
        if (strlen (location_as_posix_path) >= MAX_PATH - 1)
 
318
          /* A sign of buffer overflow or path truncation.  */
 
319
          return FALSE;
 
320
        shared_library_fullname = strdup (location_as_posix_path);
 
321
#else
 
322
        shared_library_fullname = strdup (location);
 
323
#endif
 
324
      }
 
325
    }
 
326
 
 
327
  return TRUE;
 
328
}
 
329
 
 
330
#else /* Unix except Cygwin */
 
331
 
 
332
static void
 
333
find_shared_library_fullname ()
 
334
{
 
335
#if defined __linux__ && __GLIBC__ >= 2
 
336
  /* Linux has /proc/self/maps. glibc 2 has the getline() function.  */
 
337
  FILE *fp;
 
338
 
 
339
  /* Open the current process' maps file.  It describes one VMA per line.  */
 
340
  fp = fopen ("/proc/self/maps", "r");
 
341
  if (fp)
 
342
    {
 
343
      unsigned long address = (unsigned long) &find_shared_library_fullname;
 
344
      for (;;)
 
345
        {
 
346
          unsigned long start, end;
 
347
          int c;
 
348
 
 
349
          if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
 
350
            break;
 
351
          if (address >= start && address <= end - 1)
 
352
            {
 
353
              /* Found it.  Now see if this line contains a filename.  */
 
354
              while (c = getc (fp), c != EOF && c != '\n' && c != '/')
 
355
                continue;
 
356
              if (c == '/')
 
357
                {
 
358
                  size_t size;
 
359
                  int len;
 
360
 
 
361
                  ungetc (c, fp);
 
362
                  shared_library_fullname = NULL; size = 0;
 
363
                  len = getline (&shared_library_fullname, &size, fp);
 
364
                  if (len >= 0)
 
365
                    {
 
366
                      /* Success: filled shared_library_fullname.  */
 
367
                      if (len > 0 && shared_library_fullname[len - 1] == '\n')
 
368
                        shared_library_fullname[len - 1] = '\0';
 
369
                    }
 
370
                }
 
371
              break;
 
372
            }
 
373
          while (c = getc (fp), c != EOF && c != '\n')
 
374
            continue;
 
375
        }
 
376
      fclose (fp);
 
377
    }
 
378
#endif
 
379
}
 
380
 
 
381
#endif /* (WIN32 or Cygwin) / (Unix except Cygwin) */
 
382
 
 
383
/* Return the full pathname of the current shared library.
 
384
   Return NULL if unknown.
 
385
   Guaranteed to work only on Linux, Cygwin and Woe32.  */
 
386
static char *
 
387
get_shared_library_fullname ()
 
388
{
 
389
#if !(defined _WIN32 || defined __WIN32__ || defined __CYGWIN__)
 
390
  static bool tried_find_shared_library_fullname;
 
391
  if (!tried_find_shared_library_fullname)
 
392
    {
 
393
      find_shared_library_fullname ();
 
394
      tried_find_shared_library_fullname = true;
 
395
    }
 
396
#endif
 
397
  return shared_library_fullname;
 
398
}
 
399
 
 
400
#endif /* PIC */
 
401
 
 
402
/* Returns the pathname, relocated according to the current installation
 
403
   directory.  */
 
404
const char *
 
405
relocate (const char *pathname)
 
406
{
 
407
#if defined PIC && defined INSTALLDIR
 
408
  static int initialized;
 
409
 
 
410
  /* Initialization code for a shared library.  */
 
411
  if (!initialized)
 
412
    {
 
413
      /* At this point, orig_prefix and curr_prefix likely have already been
 
414
         set through the main program's set_program_name_and_installdir
 
415
         function.  This is sufficient in the case that the library has
 
416
         initially been installed in the same orig_prefix.  But we can do
 
417
         better, to also cover the cases that 1. it has been installed
 
418
         in a different prefix before being moved to orig_prefix and (later)
 
419
         to curr_prefix, 2. unlike the program, it has not moved away from
 
420
         orig_prefix.  */
 
421
      const char *orig_installprefix = INSTALLPREFIX;
 
422
      const char *orig_installdir = INSTALLDIR;
 
423
      const char *curr_prefix_better;
 
424
 
 
425
      curr_prefix_better =
 
426
        compute_curr_prefix (orig_installprefix, orig_installdir,
 
427
                             get_shared_library_fullname ());
 
428
      if (curr_prefix_better == NULL)
 
429
        curr_prefix_better = curr_prefix;
 
430
 
 
431
      set_relocation_prefix (orig_installprefix, curr_prefix_better);
 
432
 
 
433
      initialized = 1;
 
434
    }
 
435
#endif
 
436
 
 
437
  /* Note: It is not necessary to perform case insensitive comparison here,
 
438
     even for DOS-like filesystems, because the pathname argument was
 
439
     typically created from the same Makefile variable as orig_prefix came
 
440
     from.  */
 
441
  if (orig_prefix != NULL && curr_prefix != NULL
 
442
      && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
 
443
    {
 
444
      if (pathname[orig_prefix_len] == '\0')
 
445
        /* pathname equals orig_prefix.  */
 
446
        return curr_prefix;
 
447
      if (ISSLASH (pathname[orig_prefix_len]))
 
448
        {
 
449
          /* pathname starts with orig_prefix.  */
 
450
          const char *pathname_tail = &pathname[orig_prefix_len];
 
451
          char *result =
 
452
            (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
 
453
 
 
454
#ifdef NO_XMALLOC
 
455
          if (result != NULL)
 
456
#endif
 
457
            {
 
458
              memcpy (result, curr_prefix, curr_prefix_len);
 
459
              strcpy (result + curr_prefix_len, pathname_tail);
 
460
              return result;
 
461
            }
 
462
        }
 
463
    }
 
464
  /* Nothing to relocate.  */
 
465
  return pathname;
 
466
}
 
467
 
 
468
#endif