]> sourceware.org Git - glibc.git/blob - elf/ldconfig.c
Update.
[glibc.git] / elf / ldconfig.c
1 /* Copyright (C) 1999, 2000 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 <alloca.h>
21 #include <argp.h>
22 #include <dirent.h>
23 #include <elf.h>
24 #include <error.h>
25 #include <errno.h>
26 #include <libintl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/fcntl.h>
32 #include <sys/mman.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35
36 #include "ldconfig.h"
37 #include "dl-cache.h"
38
39 /* We don't need this here - silence the compiler. */
40 #define _dl_sysdep_message(string, args...) do {} while (0);
41
42 #include "dl-procinfo.h"
43
44 #ifndef LD_SO_CONF
45 # define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
46 #endif
47
48 /* Get libc version number. */
49 #include <version.h>
50
51 #define PACKAGE _libc_intl_domainname
52
53 struct lib_entry
54 {
55 int flags;
56 unsigned long int hwcap;
57 char *lib;
58 char *path;
59 };
60
61 static const struct
62 {
63 const char *name;
64 int flag;
65 } lib_types [] =
66 {
67 {"libc4", FLAG_LIBC4},
68 {"libc5", FLAG_ELF_LIBC5},
69 {"libc6", FLAG_ELF_LIBC6},
70 {"glibc2", FLAG_ELF_LIBC6}
71 };
72
73
74 /* List of directories to handle. */
75 struct dir_entry
76 {
77 char *path;
78 int flag;
79 struct dir_entry *next;
80 };
81
82 /* The list is unsorted, contains no duplicates. Entries are added at
83 the end. */
84 static struct dir_entry *dir_entries;
85
86 /* Flags for different options. */
87 /* Print Cache. */
88 static int opt_print_cache = 0;
89
90 /* Be verbose. */
91 int opt_verbose = 0;
92
93 /* Format to support. */
94 /* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */
95 int opt_format = 1;
96
97 /* Build cache. */
98 static int opt_build_cache = 1;
99
100 /* Generate links. */
101 static int opt_link = 1;
102
103 /* Only process directories specified on the command line. */
104 static int opt_only_cline = 0;
105
106 /* Path to root for chroot. */
107 static char *opt_chroot;
108
109 /* Manually link given shared libraries. */
110 static int opt_manual_link = 0;
111
112 /* Cache file to use. */
113 static const char *cache_file;
114
115 /* Configuration file. */
116 static const char *config_file;
117
118 /* Name and version of program. */
119 static void print_version (FILE *stream, struct argp_state *state);
120 void (*argp_program_version_hook) (FILE *, struct argp_state *)
121 = print_version;
122
123 /* Definitions of arguments for argp functions. */
124 static const struct argp_option options[] =
125 {
126 { "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
127 { "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
128 { NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
129 { NULL, 'X', NULL, 0, N_("Don't generate links"), 0},
130 { NULL, 'r', "ROOT", 0, N_("Change to and use ROOT as root directory"), 0},
131 { NULL, 'C', "CACHE", 0, N_("Use CACHE as cache file"), 0},
132 { NULL, 'f', "CONF", 0, N_("Use CONF as configuration file"), 0},
133 { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
134 { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
135 { "format", 'c', "FORMAT", 0, N_("Format to use: new, old or compat (default)"), 0},
136 { NULL, 0, NULL, 0, NULL, 0 }
137 };
138
139 /* Short description of program. */
140 static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
141
142 /* Prototype for option handler. */
143 static error_t parse_opt (int key, char *arg, struct argp_state *state);
144
145 /* Data structure to communicate with argp functions. */
146 static struct argp argp =
147 {
148 options, parse_opt, NULL, doc, NULL, NULL, NULL
149 };
150
151 /* Check if string corresponds to an important hardware capability. */
152 static int
153 is_hwcap (const char *name)
154 {
155 int hwcap_idx = _dl_string_hwcap (name);
156
157 if (hwcap_idx != -1 && ((1 << hwcap_idx) & HWCAP_IMPORTANT))
158 return 1;
159 return 0;
160 }
161
162 /* Get hwcap encoding of path. */
163 static unsigned long int
164 path_hwcap (const char *path)
165 {
166 char *str = xstrdup (path);
167 char *ptr;
168 unsigned long int hwcap = 0;
169 unsigned long int h;
170
171 size_t len;
172
173 len = strlen (str);
174 if (str[len] == '/')
175 str[len] = '\0';
176
177 /* Search pathname from the end and check for hwcap strings. */
178 for (;;)
179 {
180 ptr = strrchr (str, '/');
181
182 if (ptr == NULL)
183 break;
184
185 h = _dl_string_hwcap (ptr+1);
186
187 if (h == -1)
188 break;
189 hwcap += 1 << h;
190
191 /* Search the next part of the path. */
192 *ptr = '\0';
193 }
194
195 free (str);
196 return hwcap;
197 }
198
199 /* Handle program arguments. */
200 static error_t
201 parse_opt (int key, char *arg, struct argp_state *state)
202 {
203 switch (key)
204 {
205 case 'C':
206 cache_file = arg;
207 break;
208 case 'f':
209 config_file = arg;
210 break;
211 case 'l':
212 opt_manual_link = 1;
213 break;
214 case 'N':
215 opt_build_cache = 0;
216 break;
217 case 'n':
218 opt_build_cache = 0;
219 opt_only_cline = 1;
220 break;
221 case 'p':
222 opt_print_cache = 1;
223 break;
224 case 'r':
225 opt_chroot = arg;
226 break;
227 case 'v':
228 opt_verbose = 1;
229 break;
230 case 'X':
231 opt_link = 0;
232 break;
233 case 'c':
234 if (strcmp (arg, "old") == 0)
235 opt_format = 0;
236 else if (strcmp (arg, "compat") == 0)
237 opt_format = 1;
238 else if (strcmp (arg, "new") == 0)
239 opt_format = 2;
240 break;
241 default:
242 return ARGP_ERR_UNKNOWN;
243 }
244
245 return 0;
246 }
247
248 /* Print the version information. */
249 static void
250 print_version (FILE *stream, struct argp_state *state)
251 {
252 fprintf (stream, "ldconfig (GNU %s) %s\n", PACKAGE, VERSION);
253 fprintf (stream, gettext ("\
254 Copyright (C) %s Free Software Foundation, Inc.\n\
255 This is free software; see the source for copying conditions. There is NO\n\
256 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
257 "), "2000");
258 fprintf (stream, gettext ("Written by %s.\n"),
259 "Andreas Jaeger");
260 }
261
262 /* Add a single directory entry. */
263 static void
264 add_single_dir (struct dir_entry *entry, int verbose)
265 {
266 struct dir_entry *ptr, *prev;
267
268 ptr = dir_entries;
269 prev = ptr;
270 while (ptr != NULL)
271 {
272 /* Check for duplicates. */
273 if (strcmp (ptr->path, entry->path) == 0)
274 {
275 if (opt_verbose && verbose)
276 error (0, 0, _("Path `%s' given more than once"), entry->path);
277 /* Use the newer information. */
278 ptr->flag = entry->flag;
279 free (entry);
280 break;
281 }
282 prev = ptr;
283 ptr = ptr->next;
284 }
285 /* Is this the first entry? */
286 if (ptr == NULL && dir_entries == NULL)
287 dir_entries = entry;
288 else if (ptr == NULL)
289 prev->next = entry;
290 }
291
292 /* Add one directory to the list of directories to process. */
293 static void
294 add_dir (const char *line)
295 {
296 char *equal_sign;
297 struct dir_entry *entry;
298 unsigned int i;
299
300 entry = xmalloc (sizeof (struct dir_entry));
301 entry->next = NULL;
302
303 /* Search for an '=' sign. */
304 entry->path = xstrdup (line);
305 equal_sign = strchr (entry->path, '=');
306 if (equal_sign)
307 {
308 *equal_sign = '\0';
309 ++equal_sign;
310 entry->flag = FLAG_ANY;
311 for (i = 0; i < sizeof (lib_types) / sizeof (lib_types [0]); ++i)
312 if (strcmp (equal_sign, lib_types[i].name) == 0)
313 {
314 entry->flag = lib_types[i].flag;
315 break;
316 }
317 if (entry->flag == FLAG_ANY)
318 error (0, 0, _("%s is not a known library type"), equal_sign);
319 }
320 else
321 {
322 entry->flag = FLAG_ANY;
323 }
324
325 /* Canonify path: for now only remove trailing slashes. */
326 i = strlen (entry->path) - 1;
327 while (entry->path[i] == '/' && i > 0)
328 {
329 entry->path [i] = '\0';
330 --i;
331 }
332
333 add_single_dir (entry, 1);
334 }
335
336
337 /* Create a symbolic link from soname to libname in directory path. */
338 static void
339 create_links (const char *path, const char *libname, const char *soname)
340 {
341 char *full_libname, *full_soname;
342 struct stat stat_lib, stat_so, lstat_so;
343 int do_link = 1;
344 int do_remove = 1;
345 /* XXX: The logics in this function should be simplified. */
346
347 /* Get complete path. */
348 full_libname = alloca (strlen (path) + strlen (libname) + 2);
349 full_soname = alloca (strlen (path) + strlen (libname) + 2);
350 sprintf (full_libname, "%s/%s", path, libname);
351 sprintf (full_soname, "%s/%s", path, soname);
352
353 /* Does soname already exist and point to the right library? */
354 if (stat (full_soname, &stat_so) == 0)
355 {
356 if (stat (full_libname, &stat_lib))
357 {
358 error (0, 0, _("Can't stat %s\n"), full_libname);
359 return;
360 }
361 if (stat_lib.st_dev == stat_so.st_dev
362 && stat_lib.st_ino == stat_so.st_ino)
363 /* Link is already correct. */
364 do_link = 0;
365 else if (lstat (full_soname, &lstat_so) == 0
366 && !S_ISLNK (lstat_so.st_mode))
367 {
368 error (0, 0, _("%s is not a symbolic link\n"), full_soname);
369 do_link = 0;
370 do_remove = 0;
371 }
372 }
373 else if (lstat (full_soname, &lstat_so) != 0
374 || !S_ISLNK (lstat_so.st_mode))
375 /* Unless it is a stale symlink, there is no need to remove. */
376 do_remove = 0;
377
378 if (opt_verbose)
379 printf ("\t%s -> %s", soname, libname);
380
381 if (do_link && opt_link)
382 {
383 /* Remove old link. */
384 if (do_remove)
385 if (unlink (full_soname))
386 {
387 error (0, 0, _("Can't unlink %s"), full_soname);
388 do_link = 0;
389 }
390 /* Create symbolic link. */
391 if (do_link && symlink (libname, full_soname))
392 {
393 error (0, 0, _("Can't link %s to %s"), full_soname, libname);
394 do_link = 0;
395 }
396 if (opt_verbose)
397 {
398 if (do_link)
399 fputs (_(" (changed)\n"), stdout);
400 else
401 fputs (_(" (SKIPPED)\n"), stdout);
402 }
403 }
404 else if (opt_verbose)
405 fputs ("\n", stdout);
406 }
407
408 /* Manually link the given library. */
409 static void
410 manual_link (char *library)
411 {
412 char *path;
413 char *libname;
414 char *soname;
415 struct stat stat_buf;
416 int flag;
417
418 /* Prepare arguments for create_links call. Split library name in
419 directory and filename first. Since path is allocated, we've got
420 to be careful to free at the end. */
421 path = xstrdup (library);
422 libname = strrchr (path, '/');
423
424 if (libname)
425 {
426 /* Successfully split names. Check if path is just "/" to avoid
427 an empty path. */
428 if (libname == path)
429 {
430 libname = library + 1;
431 path = xrealloc (path, 2);
432 strcpy (path, "/");
433 }
434 else
435 {
436 *libname = '\0';
437 ++libname;
438 }
439 }
440 else
441 {
442 /* There's no path, construct one. */
443 libname = library;
444 path = xrealloc (path, 2);
445 strcpy (path, ".");
446 }
447
448 /* Do some sanity checks first. */
449 if (lstat (library, &stat_buf))
450 {
451 error (0, errno, _("Can't lstat %s"), library);
452 free (path);
453 return;
454 }
455 /* We don't want links here! */
456 else if (!S_ISREG (stat_buf.st_mode))
457 {
458 error (0, 0, _("Ignored file %s since it is not a regular file."),
459 library);
460 free (path);
461 return;
462 }
463 libname = basename (library);
464 if (process_file (library, libname, &flag, &soname, 0))
465 {
466 error (0, 0, _("No link created since soname could not be found for %s"),
467 library);
468 free (path);
469 return;
470 }
471 create_links (path, libname, soname);
472 free (soname);
473 free (path);
474 }
475
476
477 /* Read a whole directory and search for libraries.
478 The purpose is two-fold:
479 - search for libraries which will be added to the cache
480 - create symbolic links to the soname for each library
481
482 This has to be done separatly for each directory.
483
484 To keep track of which libraries to add to the cache and which
485 links to create, we save a list of all libraries.
486
487 The algorithm is basically:
488 for all libraries in the directory do
489 get soname of library
490 if soname is already in list
491 if new library is newer, replace entry
492 otherwise ignore this library
493 otherwise add library to list
494
495 For example, if the two libraries libxy.so.1.1 and libxy.so.1.2
496 exist and both have the same soname, e.g. libxy.so, a symbolic link
497 is created from libxy.so.1.2 (the newer one) to libxy.so.
498 libxy.so.1.2 and libxy.so are added to the cache - but not
499 libxy.so.1.1. */
500
501 /* Information for one library. */
502 struct dlib_entry
503 {
504 char *name;
505 char *soname;
506 int flag;
507 int is_link;
508 struct dlib_entry *next;
509 };
510
511
512 static void
513 search_dir (const struct dir_entry *entry)
514 {
515 DIR *dir;
516 struct dirent *direntry;
517 char *file_name;
518 int file_name_len, len;
519 char *soname;
520 struct dlib_entry *dlibs;
521 struct dlib_entry *dlib_ptr;
522 struct stat stat_buf;
523 int is_link;
524 unsigned long int hwcap = path_hwcap (entry->path);
525
526 file_name_len = PATH_MAX;
527 file_name = alloca (file_name_len);
528
529 dlibs = NULL;
530
531 if (opt_verbose)
532 {
533 if (hwcap != 0)
534 printf ("%s: (hwcap: 0x%lx)\n", entry->path, hwcap);
535 else
536 printf ("%s:\n", entry->path);
537 }
538
539 dir = opendir (entry->path);
540 if (dir == NULL)
541 {
542 if (opt_verbose)
543 error (0, errno, _("Can't open directory %s"), entry->path);
544 return;
545 }
546
547
548 while ((direntry = readdir (dir)) != NULL)
549 {
550 int flag;
551 #ifdef _DIRENT_HAVE_D_TYPE
552 /* We only look at links and regular files. */
553 if (direntry->d_type != DT_UNKNOWN
554 && direntry->d_type != DT_LNK
555 && direntry->d_type != DT_REG
556 && direntry->d_type != DT_DIR)
557 continue;
558 #endif /* _DIRENT_HAVE_D_TYPE */
559 /* Does this file look like a shared library or is it a hwcap
560 subdirectory? The dynamic linker is also considered as
561 shared library. */
562 if (((strncmp (direntry->d_name, "lib", 3) != 0
563 && strncmp (direntry->d_name, "ld-", 3) != 0)
564 || strstr (direntry->d_name, ".so") == NULL)
565 && !is_hwcap (direntry->d_name))
566 continue;
567 len = strlen (entry->path) + strlen (direntry->d_name);
568 if (len > file_name_len)
569 {
570 file_name_len = len + 1;
571 file_name = alloca (file_name_len);
572 }
573 sprintf (file_name , "%s/%s", entry->path, direntry->d_name);
574 #ifdef _DIRENT_HAVE_D_TYPE
575 if (direntry->d_type != DT_UNKNOWN)
576 stat_buf.st_mode = DTTOIF (direntry->d_type);
577 else
578 #endif
579 if (lstat (file_name, &stat_buf))
580 {
581 error (0, errno, _("Can't lstat %s"), file_name);
582 continue;
583 }
584
585 if (S_ISDIR (stat_buf.st_mode) && is_hwcap (direntry->d_name))
586 {
587 /* Handle subdirectory later. */
588 struct dir_entry *new_entry;
589
590 new_entry = xmalloc (sizeof (struct dir_entry));
591 new_entry->path = xstrdup (file_name);
592 new_entry->flag = entry->flag;
593 new_entry->next = NULL;
594 add_single_dir (new_entry, 0);
595 continue;
596 }
597 else if (!S_ISREG (stat_buf.st_mode) && !S_ISLNK (stat_buf.st_mode))
598 continue;
599
600 is_link = S_ISLNK (stat_buf.st_mode);
601
602 if (process_file (file_name, direntry->d_name, &flag, &soname, is_link))
603 continue;
604
605 /* Links will just point to itself. */
606 if (is_link)
607 {
608 free (soname);
609 soname = xstrdup (direntry->d_name);
610 }
611
612 if (flag == FLAG_ELF
613 && (entry->flag == FLAG_ELF_LIBC5
614 || entry->flag == FLAG_ELF_LIBC6))
615 flag = entry->flag;
616 /* Some sanity checks to print warnings. */
617 if (opt_verbose)
618 {
619 if (flag == FLAG_ELF_LIBC5 && entry->flag != FLAG_ELF_LIBC5
620 && entry->flag != FLAG_ANY)
621 error (0, 0, _("libc5 library %s in wrong directory"), file_name);
622 if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6
623 && entry->flag != FLAG_ANY)
624 error (0, 0, _("libc6 library %s in wrong directory"), file_name);
625 if (flag == FLAG_LIBC4 && entry->flag != FLAG_LIBC4
626 && entry->flag != FLAG_ANY)
627 error (0, 0, _("libc4 library %s in wrong directory"), file_name);
628 }
629
630 /* Add library to list. */
631 for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
632 {
633 /* Is soname already in list? */
634 if (strcmp (dlib_ptr->soname, soname) == 0)
635 {
636 /* Prefer a file to a link, otherwise check which one
637 is newer. */
638 if ((!is_link && dlib_ptr->is_link)
639 || (is_link == dlib_ptr->is_link
640 && _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
641 {
642 /* It's newer - add it. */
643 /* Flag should be the same - sanity check. */
644 if (dlib_ptr->flag != flag)
645 {
646 if (dlib_ptr->flag == FLAG_ELF
647 && (flag == FLAG_ELF_LIBC5 || flag == FLAG_ELF_LIBC6))
648 dlib_ptr->flag = flag;
649 else if ((dlib_ptr->flag == FLAG_ELF_LIBC5
650 || dlib_ptr->flag == FLAG_ELF_LIBC6)
651 && flag == FLAG_ELF)
652 dlib_ptr->flag = flag;
653 else
654 error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
655 dlib_ptr->name, direntry->d_name, entry->path);
656 }
657 free (dlib_ptr->name);
658 dlib_ptr->name = xstrdup (direntry->d_name);
659 dlib_ptr->is_link = is_link;
660 }
661 /* Don't add this library, abort loop. */
662 /* Also free soname, since it's dynamically allocated. */
663 free (soname);
664 break;
665 }
666 }
667 /* Add the library if it's not already in. */
668 if (dlib_ptr == NULL)
669 {
670 dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
671 dlib_ptr->name = xstrdup (direntry->d_name);
672 dlib_ptr->flag = flag;
673 dlib_ptr->soname = soname;
674 dlib_ptr->is_link = is_link;
675 /* Add at head of list. */
676 dlib_ptr->next = dlibs;
677 dlibs = dlib_ptr;
678 }
679 }
680
681 closedir (dir);
682
683 /* Now dlibs contains a list of all libs - add those to the cache
684 and created all symbolic links. */
685 for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
686 {
687 /* Don't create links to links. */
688 if (dlib_ptr->is_link == 0)
689 create_links (entry->path, dlib_ptr->name, dlib_ptr->soname);
690 if (opt_build_cache)
691 add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag, hwcap);
692 }
693
694 /* Free all resources. */
695 while (dlibs)
696 {
697 dlib_ptr = dlibs;
698 free (dlib_ptr->soname);
699 free (dlib_ptr->name);
700 dlibs = dlibs->next;
701 free (dlib_ptr);
702 }
703 }
704
705 /* Search through all libraries. */
706 static void
707 search_dirs (void)
708 {
709 struct dir_entry *entry;
710
711 for (entry = dir_entries; entry != NULL; entry = entry->next)
712 search_dir (entry);
713
714 /* Free all allocated memory. */
715 while (dir_entries)
716 {
717 entry = dir_entries;
718 dir_entries = dir_entries->next;
719 free (entry->path);
720 free (entry);
721 }
722 }
723
724
725 /* Parse configuration file. */
726 static void
727 parse_conf (const char *filename)
728 {
729 FILE *file;
730 char *line = NULL;
731 size_t len = 0;
732
733 file = fopen (filename, "r");
734
735 if (file == NULL)
736 {
737 error (0, errno, _("Can't open configuration file %s%s%s"),
738 opt_chroot ?: "", opt_chroot ? "/" : "", filename);
739 return;
740 }
741
742 do
743 {
744 ssize_t n = getline (&line, &len, file);
745 if (n < 0)
746 break;
747
748 if (line[n - 1] == '\n')
749 line[n - 1] = '\0';
750
751 /* Because the file format does not know any form of quoting we
752 can search forward for the next '#' character and if found
753 make it terminating the line. */
754 *strchrnul (line, '#') = '\0';
755
756 /* If the line is blank it is ignored. */
757 if (line[0] == '\0')
758 continue;
759
760 add_dir (line);
761 } while (!feof (file));
762
763 /* Free buffer and close file. */
764 free (line);
765 fclose (file);
766 }
767
768
769 int
770 main (int argc, char **argv)
771 {
772 int remaining;
773
774 /* Parse and process arguments. */
775 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
776
777 /* Remaining arguments are additional libraries if opt_manual_link
778 is not set. */
779 if (remaining != argc && !opt_manual_link)
780 {
781 int i;
782 for (i = remaining; i < argc; ++i)
783 add_dir (argv [i]);
784 }
785
786 if (cache_file == NULL)
787 cache_file = LD_SO_CACHE;
788
789 if (config_file == NULL)
790 config_file = LD_SO_CONF;
791
792 /* Chroot first. */
793 if (opt_chroot)
794 {
795 /* Normalize the path a bit, we might need it for printing later. */
796 char *endp = strchr (opt_chroot, '\0');
797 while (endp > opt_chroot + 1 && endp[-1] == '/')
798 --endp;
799 *endp = '\0';
800
801 if (chroot (opt_chroot))
802 /* Report failure and exit program. */
803 error (EXIT_FAILURE, errno, _("Can't chroot to %s"), opt_chroot);
804 /* chroot doesn't change the working directory, let's play safe. */
805 if (chdir ("/"))
806 error (EXIT_FAILURE, errno, _("Can't chdir to /"));
807 }
808
809 if (opt_print_cache)
810 {
811 print_cache (cache_file);
812 exit (0);
813 }
814
815 if (opt_manual_link)
816 {
817 /* Link all given libraries manually. */
818 int i;
819
820 for (i = remaining; i < argc; ++i)
821 manual_link (argv [i]);
822
823 exit (0);
824 }
825
826
827 if (opt_build_cache)
828 init_cache ();
829
830 if (!opt_only_cline)
831 {
832 /* Always add the standard search paths. */
833 add_dir (SLIBDIR);
834 if (strcmp (SLIBDIR, LIBDIR))
835 add_dir (LIBDIR);
836
837 parse_conf (config_file);
838 }
839
840 search_dirs ();
841
842 if (opt_build_cache)
843 save_cache (cache_file);
844
845 return 0;
846 }
This page took 0.073667 seconds and 5 git commands to generate.