]> sourceware.org Git - glibc.git/blame - elf/ldconfig.c
Update.
[glibc.git] / elf / ldconfig.c
CommitLineData
591e1ffb
UD
1/* Copyright (C) 1999 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Andreas Jaeger <aj@suse.de>, 1999.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library 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 the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20#include <argp.h>
21#include <dirent.h>
22#include <error.h>
23#include <errno.h>
24#include <libintl.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include <sys/fcntl.h>
30#include <sys/mman.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33
34#include "ldconfig.h"
35
36#ifndef LD_SO_CACHE
37# define LD_SO_CACHE "/etc/ld.so.cache"
38#endif
39
40#ifndef LD_SO_CONF
41# define LD_SO_CONF "/etc/ld.so.conf"
42#endif
43
44/* Get libc version number. */
45#include <version.h>
46
47#define PACKAGE _libc_intl_domainname
48
49struct lib_entry
50 {
51 int flags;
52 char *lib;
53 char *path;
54 };
55
56static const struct
57{
58 const char *name;
59 int flag;
60} lib_types [] =
61{
62 {"libc4", FLAG_LIBC4},
63 {"libc5", FLAG_ELF_LIBC5},
64 {"libc6", FLAG_ELF_LIBC6},
65 {"glibc2", FLAG_ELF_LIBC6}
66};
67
68
69/* List of directories to handle. */
70struct dir_entry
71{
72 char *path;
73 int flag;
74 struct dir_entry *next;
75};
76
77/* The list is unsorted, contains no duplicates. Entries are added at
78 the end. */
79static struct dir_entry *dir_entries;
80
81/* Flags for different options. */
82/* Print Cache. */
83static int opt_print_cache = 0;
84
85/* Be verbose. */
86int opt_verbose = 0;
87
88/* Build cache. */
89static int opt_build_cache = 1;
90
91/* Generate links. */
92static int opt_link = 1;
93
94/* Only process directories specified on the command line. */
95static int opt_only_cline = 0;
96
97/* Path to root for chroot. */
98static char *opt_chroot;
99
100/* Cache file to use. */
101static const char *cache_file;
102
103/* Configuration file. */
104static const char *config_file;
105
106/* Name and version of program. */
107static void print_version (FILE *stream, struct argp_state *state);
108void (*argp_program_version_hook) (FILE *, struct argp_state *)
109 = print_version;
110
111/* Definitions of arguments for argp functions. */
112static const struct argp_option options[] =
113{
114 { "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
115 { "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
116 { NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
117 { NULL, 'X', NULL, 0, N_("Don't generate links"), 0},
118 { NULL, 'r', "ROOT", 0, N_("Change to and use ROOT as root directory"), 0},
119 { NULL, 'C', "CACHE", 0, N_("Use CACHE as cache file"), 0},
120 { NULL, 'f', "CONF", 0, N_("Use CONF as configuration file"), 0},
121 { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
122 { NULL, 0, NULL, 0, NULL, 0 }
123};
124
125/* Short description of program. */
126static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
127
128/* Prototype for option handler. */
129static error_t parse_opt (int key, char *arg, struct argp_state *state);
130
131/* Data structure to communicate with argp functions. */
132static struct argp argp =
133{
134 options, parse_opt, NULL, doc, NULL, NULL, NULL
135};
136
137
138
139/* Handle program arguments. */
140static error_t
141parse_opt (int key, char *arg, struct argp_state *state)
142{
143 switch (key)
144 {
145 case 'C':
146 cache_file = arg;
147 break;
148 case 'f':
149 config_file = arg;
150 break;
151 case 'N':
152 opt_build_cache = 0;
153 break;
154 case 'n':
155 opt_build_cache = 0;
156 opt_only_cline = 1;
157 break;
158 case 'p':
159 opt_print_cache = 1;
160 break;
161 case 'r':
162 opt_chroot = arg;
163 break;
164 case 'v':
165 opt_verbose = 1;
166 break;
167 case 'X':
168 opt_link = 0;
169 break;
170 default:
171 return ARGP_ERR_UNKNOWN;
172 }
173
174 return 0;
175}
176
177/* Print the version information. */
178static void
179print_version (FILE *stream, struct argp_state *state)
180{
181 fprintf (stream, "ldconfig (GNU %s) %s\n", PACKAGE, VERSION);
182 fprintf (stream, gettext ("\
183Copyright (C) %s Free Software Foundation, Inc.\n\
184This is free software; see the source for copying conditions. There is NO\n\
185warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
186"), "1999");
187 fprintf (stream, gettext ("Written by %s.\n"),
188 "Andreas Jaeger");
189}
190
191/* Add one directory to the list of directories to process. */
192static void
193add_dir (const char *line)
194{
195 char *equal_sign;
196 struct dir_entry *entry, *ptr, *prev;
197 unsigned int i;
198
199 entry = xmalloc (sizeof (struct dir_entry));
200 entry->next = NULL;
201
202 /* Search for an '=' sign. */
203 entry->path = xstrdup (line);
204 equal_sign = strchr (entry->path, '=');
205 if (equal_sign)
206 {
207 *equal_sign = '\0';
208 ++equal_sign;
209 entry->flag = FLAG_ANY;
210 for (i = 0; i < sizeof (lib_types) / sizeof (lib_types [0]); ++i)
211 if (strcmp (equal_sign, lib_types[i].name) == 0)
212 {
213 entry->flag = lib_types[i].flag;
214 break;
215 }
216 if (entry->flag == FLAG_ANY)
217 error (0, 0, _("%s is not a known library type"), equal_sign);
218 }
219 else
220 {
221 entry->flag = FLAG_ANY;
222 }
223
224 /* Canonify path: for now only remove trailing slashes. */
225 i = strlen (entry->path) - 1;
226 while (entry->path[i] == '/' && i > 0)
227 {
228 entry->path [i] = '\0';
229 --i;
230 }
231
232 ptr = dir_entries;
233 prev = ptr;
234 while (ptr != NULL)
235 {
236 /* Check for duplicates. */
237 if (strcmp (ptr->path, entry->path) == 0)
238 {
239 if (opt_verbose)
240 error (0, 0, _("Path `%s' given more than once"), entry->path);
241 /* Use the newer information. */
242 ptr->flag = entry->flag;
243 free (entry);
244 break;
245 }
246 prev = ptr;
247 ptr = ptr->next;
248 }
249 /* Is this the first entry? */
250 if (ptr == NULL && dir_entries == NULL)
251 dir_entries = entry;
252 else if (ptr == NULL)
253 prev->next = entry;
254}
255
256
257/* Create a symbolic link from soname to libname in directory path. */
258static void
259create_links (const char *path, const char *libname, const char *soname)
260{
261 char full_libname [PATH_MAX], full_soname [PATH_MAX];
262 struct stat stat_lib, stat_so, lstat_so;
263 int do_link = 1;
264 int do_remove = 1;
265 /* XXX: The logics in this function should be simplified. */
266
267 /* Get complete path. */
268 snprintf (full_libname, sizeof full_libname, "%s/%s", path, libname);
269 snprintf (full_soname, sizeof full_soname, "%s/%s", path, soname);
270
271 /* Does soname already exist and point to the right library? */
272 if (stat (full_soname, &stat_so) == 0)
273 {
274 if (stat (full_libname, &stat_lib))
275 {
276 error (0, 0, _("Can't stat %s\n"), full_libname);
277 return;
278 }
279 if (stat_lib.st_dev == stat_so.st_dev
280 && stat_lib.st_ino == stat_so.st_ino)
281 /* Link is already correct. */
282 do_link = 0;
283 else if (lstat (full_soname, &lstat_so) == 0
284 && !S_ISLNK (lstat_so.st_mode))
285 {
286 error (0, 0, _("%s is not a symbolic link\n"), full_soname);
287 do_link = 0;
288 do_remove = 0;
289 }
290 }
291 else if (lstat (full_soname, &lstat_so) != 0
292 || !S_ISLNK (lstat_so.st_mode))
293 /* Unless it is a stale symlink, there is no need to remove. */
294 do_remove = 0;
295
296 if (opt_verbose)
297 printf ("\t%s -> %s", soname, libname);
298
299 if (do_link && opt_link)
300 {
301 /* Remove old link. */
302 if (do_remove)
303 if (unlink (full_soname))
304 {
305 error (0, 0, _("Can't unlink %s"), full_soname);
306 do_link = 0;
307 }
308 /* Create symbolic link. */
309 if (do_link && symlink (libname, full_soname))
310 {
311 error (0, 0, _("Can't link %s to %s"), full_soname, libname);
312 do_link = 0;
313 }
314 if (opt_verbose)
315 {
316 if (do_link)
317 fputs (_(" (changed)\n"), stdout);
318 else
319 fputs (_(" (SKIPPED)\n"), stdout);
320 }
321 }
322 else if (opt_verbose)
323 fputs ("\n", stdout);
324}
325
326/* Read a whole directory and search for libraries.
327 The purpose is two-fold:
328 - search for libraries which will be added to the cache
329 - create symbolic links to the soname for each library
330
331 This has to be done separatly for each directory.
332
333 To keep track of which libraries to add to the cache and which
334 links to create, we save a list of all libraries.
335
336 The algorithm is basically:
337 for all libraries in the directory do
338 get soname of library
339 if soname is already in list
340 if new library is newer, replace entry
341 otherwise ignore this library
342 otherwise add library to list
343
344 For example, if the two libraries libxy.so.1.1 and libxy.so.1.2
345 exist and both have the same soname, e.g. libxy.so, a symbolic link
346 is created from libxy.so.1.2 (the newer one) to libxy.so.
347 libxy.so.1.2 and libxy.so are added to the cache - but not
348 libxy.so.1.1. */
349
350/* Information for one library. */
351struct dlib_entry
352{
353 char *name;
354 char *soname;
355 int flag;
356 int is_link;
357 struct dlib_entry *next;
358};
359
360
361static void
362search_dir (const struct dir_entry *entry)
363{
364 DIR *dir;
365 struct dirent *direntry;
366 char buf [PATH_MAX];
367 char *soname;
368 struct dlib_entry *dlibs;
369 struct dlib_entry *dlib_ptr;
370 int nchars;
371 struct stat stat_buf;
372 int is_link;
373
374 dlibs = NULL;
375
376 if (opt_verbose)
377 printf ("%s:\n", entry->path);
378
379 dir = opendir (entry->path);
380 if (dir == NULL)
381 {
382 if (opt_verbose)
383 error (0, errno, _("Can't open directory %s"), entry->path);
384 return;
385 }
386
387
388 while ((direntry = readdir (dir)) != NULL)
389 {
390 int flag;
391#ifdef _DIRENT_HAVE_D_TYPE
392 /* We only look at links and regular files. */
393 if (direntry->d_type != DT_UNKNOWN
394 && direntry->d_type != DT_LNK
395 && direntry->d_type != DT_REG)
396 continue;
397#endif /* _DIRENT_HAVE_D_TYPE */
398
399 /* Does this file look like a shared library? The dynamic
400 linker is also considered as shared library. */
401 if ((strncmp (direntry->d_name, "lib", 3) != 0
402 && strncmp (direntry->d_name, "ld-", 3) != 0)
403 || strstr (direntry->d_name, ".so") == NULL)
404 continue;
405 nchars = snprintf (buf, sizeof (buf), "%s/%s", entry->path,
406 direntry->d_name);
407 /* Check for overflow. */
408 if (nchars >= (int) sizeof (buf))
409 {
410 error (0, 0, _("buffer for snprintf too small for %s/%s--file is ignored\n"),
411 entry->path, direntry->d_name);
412 continue;
413 }
414 if (lstat (buf, &stat_buf))
415 {
416 error (0, errno, _("Can't lstat %s"), buf);
417 continue;
418 }
419 else if (!S_ISREG (stat_buf.st_mode) && !S_ISLNK (stat_buf.st_mode))
420 continue;
421
422 is_link = S_ISLNK (stat_buf.st_mode);
423
424 if (process_file (buf, direntry->d_name, &flag, &soname, is_link))
425 continue;
426
427 /* Links will just point to itself. */
428 if (is_link)
429 {
430 free (soname);
431 soname = xstrdup (direntry->d_name);
432 }
433
434 if (flag == FLAG_ELF
435 && (entry->flag == FLAG_ELF_LIBC5
436 || entry->flag == FLAG_ELF_LIBC6))
437 flag = entry->flag;
438 /* Some sanity checks to print warnings. */
439 if (opt_verbose)
440 {
441 if (flag == FLAG_ELF_LIBC5 && entry->flag != FLAG_ELF_LIBC5
442 && entry->flag != FLAG_ANY)
443 error (0, 0, _("libc5 library %s in wrong directory"), buf);
444 if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6
445 && entry->flag != FLAG_ANY)
446 error (0, 0, _("libc6 library %s in wrong directory"), buf);
447 if (flag == FLAG_LIBC4 && entry->flag != FLAG_LIBC4
448 && entry->flag != FLAG_ANY)
449 error (0, 0, _("libc4 library %s in wrong directory"), buf);
450 }
451
452 /* Add library to list. */
453 for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
454 {
455 /* Is soname already in list? */
456 if (strcmp (dlib_ptr->soname, soname) == 0)
457 {
458 /* Prefer a file to a link, otherwise check which one
459 is newer. */
460 if ((!is_link && dlib_ptr->is_link)
461 || (is_link == dlib_ptr->is_link
462 && cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
463 {
464 /* It's newer - add it. */
465 /* Flag should be the same - sanity check. */
466 if (dlib_ptr->flag != flag)
467 {
468 if (dlib_ptr->flag == FLAG_ELF
469 && (flag == FLAG_ELF_LIBC5 || flag == FLAG_ELF_LIBC6))
470 dlib_ptr->flag = flag;
471 else if ((dlib_ptr->flag == FLAG_ELF_LIBC5
472 || dlib_ptr->flag == FLAG_ELF_LIBC6)
473 && flag == FLAG_ELF)
474 dlib_ptr->flag = flag;
475 else
476 error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
477 dlib_ptr->name, direntry->d_name, entry->path);
478 }
479 free (dlib_ptr->name);
480 dlib_ptr->name = xstrdup (direntry->d_name);
481 dlib_ptr->is_link = is_link;
482 }
483 /* Don't add this library, abort loop. */
484 /* Also free soname, since it's dynamically allocated. */
485 free (soname);
486 break;
487 }
488 }
489 /* Add the library if it's not already in. */
490 if (dlib_ptr == NULL)
491 {
492 dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
493 dlib_ptr->name = xstrdup (direntry->d_name);
494 dlib_ptr->flag = flag;
495 dlib_ptr->soname = soname;
496 dlib_ptr->is_link = is_link;
497 /* Add at head of list. */
498 dlib_ptr->next = dlibs;
499 dlibs = dlib_ptr;
500 }
501 }
502
503 closedir (dir);
504
505 /* Now dlibs contains a list of all libs - add those to the cache
506 and created all symbolic links. */
507 for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
508 {
509 /* Don't create links to links. */
510 if (dlib_ptr->is_link == 0)
511 create_links (entry->path, dlib_ptr->name, dlib_ptr->soname);
512 if (opt_build_cache)
513 add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag);
514 }
515
516 /* Free all resources. */
517 while (dlibs)
518 {
519 dlib_ptr = dlibs;
520 free (dlib_ptr->soname);
521 free (dlib_ptr->name);
522 dlibs = dlibs->next;
523 free (dlib_ptr);
524 }
525}
526
527/* Search through all libraries. */
528static void
529search_dirs (void)
530{
531 struct dir_entry *entry;
532
533 for (entry = dir_entries; entry != NULL; entry = entry->next)
534 search_dir (entry);
535
536 /* Free all allocated memory. */
537 while (dir_entries)
538 {
539 entry = dir_entries;
540 dir_entries = dir_entries->next;
541 free (entry->path);
542 free (entry);
543 }
544}
545
546
547/* Parse configuration file. */
548static void
549parse_conf (const char *filename)
550{
551 FILE *file;
552 char *line = NULL;
553 size_t len = 0;
554
555 file = fopen (filename, "r");
556
557 if (file == NULL)
558 {
559 error (0, errno, _("Can't open configuration file %s"), filename);
560 return;
561 }
562
563 do
564 {
565 ssize_t n = getline (&line, &len, file);
566 if (n < 0)
567 break;
568
569 if (line[n - 1] == '\n')
570 line[n - 1] = '\0';
571
572 /* Because the file format does not know any form of quoting we
573 can search forward for the next '#' character and if found
574 make it terminating the line. */
575 *strchrnul (line, '#') = '\0';
576
577 /* If the line is blank it is ignored. */
578 if (line[0] == '\0')
579 continue;
580
581 add_dir (line);
582 } while (!feof (file));
583
584 /* Free buffer and close file. */
585 free (line);
586 fclose (file);
587}
588
589
590int
591main (int argc, char **argv)
592{
593 int remaining;
594
595 /* Parse and process arguments. */
596 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
597
598 /* Remaining arguments are additional libraries. */
599 if (remaining != argc)
600 {
601 int i;
602 for (i = remaining; i < argc; ++i)
603 add_dir (argv [i]);
604 }
605
606 if (cache_file == NULL)
607 cache_file = LD_SO_CACHE;
608
609 if (config_file == NULL)
610 config_file = LD_SO_CONF;
611
612 /* Chroot first. */
613 if (opt_chroot)
614 {
615 if (chroot (opt_chroot))
616 /* Report failure and exit program. */
617 error (EXIT_FAILURE, errno, _("Can't chroot to %s"), opt_chroot);
618 /* chroot doesn't change the working directory, let's play safe. */
619 if (chdir ("/"))
620 error (EXIT_FAILURE, errno, _("Can't chdir to /"));
621 }
622
623 if (opt_print_cache)
624 {
625 print_cache (cache_file);
626 exit (0);
627 }
628
629 if (opt_build_cache)
630 init_cache ();
631
632 if (!opt_only_cline)
633 {
634 /* Always add the standard search paths. */
635 add_dir ("/lib");
636 add_dir ("/usr/lib");
637
638 parse_conf (config_file);
639 }
640
641 search_dirs ();
642
643 if (opt_build_cache)
644 save_cache (cache_file);
645
646 return 0;
647}
This page took 0.088503 seconds and 5 git commands to generate.