@@ -60,7 +60,7 @@ struct audit_list
};
/* This is a list of all the modes the dynamic loader can be in. */
-enum mode { normal, list, verify, trace };
+enum mode { normal, list, verify, trace, rtld_help };
/* Aggregated state information extracted from environment variables
and the ld.so command line. */
@@ -98,6 +98,11 @@ call_init_paths (const struct dl_main_state *state)
}
/* Print ld.so usage information and exit. */
-void _dl_usage (void) attribute_hidden __attribute__ ((__noreturn__));
+void _dl_usage (const char *argv0, const char *wrong_option)
+ attribute_hidden __attribute__ ((__noreturn__));
+
+/* Print ld.so --help output and exit. */
+void _dl_help (const char *argv0, struct dl_main_state *state)
+ attribute_hidden __attribute__ ((__noreturn__));
#endif /* _DL_MAIN */
@@ -19,12 +19,24 @@
#include <dl-cache.h>
#include <dl-main.h>
#include <ldsodefs.h>
+#include <unistd.h>
void
-_dl_usage (void)
+_dl_usage (const char *argv0, const char *wrong_option)
{
- _dl_fatal_printf ("\
-Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
+ if (wrong_option != NULL)
+ _dl_error_printf ("%s: unrecognized option '%s'\n", argv0, wrong_option);
+ else
+ _dl_error_printf ("%s: missing program name\n", argv0);
+ _dl_error_printf ("Try '%s --help' for more information.\n", argv0);
+ _exit (1);
+}
+
+void
+_dl_help (const char *argv0, struct dl_main_state *state)
+{
+ _dl_printf ("\
+Usage: %s [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
You have invoked `ld.so', the helper program for shared library executables.\n\
This program usually lives in the file `/lib/ld.so', and special directives\n\
in executable files using ELF shared libraries tell the system's program\n\
@@ -46,5 +58,9 @@ of this helper program; chances are you did not intend to run this program.\n\
--inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\
in LIST\n\
--audit LIST use objects named in LIST as auditors\n\
- --preload LIST preload objects named in LIST\n");
+ --preload LIST preload objects named in LIST\n\
+ --help display this help and exit\n\
+",
+ argv0);
+ _exit (0);
}
@@ -1131,6 +1131,7 @@ dl_main (const ElfW(Phdr) *phdr,
_dl_starting_up = 1;
#endif
+ const char *argv0 = _dl_argv[0];
if (*user_entry == (ElfW(Addr)) ENTRY_POINT)
{
/* Ho ho. We are not the program interpreter! We are the program
@@ -1156,8 +1157,12 @@ dl_main (const ElfW(Phdr) *phdr,
while (_dl_argc > 1)
if (! strcmp (_dl_argv[1], "--list"))
{
- state.mode = list;
- GLRO(dl_lazy) = -1; /* This means do no dependency analysis. */
+ if (state.mode != rtld_help)
+ {
+ state.mode = list;
+ /* This means do no dependency analysis. */
+ GLRO(dl_lazy) = -1;
+ }
++_dl_skip_args;
--_dl_argc;
@@ -1165,7 +1170,8 @@ dl_main (const ElfW(Phdr) *phdr,
}
else if (! strcmp (_dl_argv[1], "--verify"))
{
- state.mode = verify;
+ if (state.mode != rtld_help)
+ state.mode = verify;
++_dl_skip_args;
--_dl_argc;
@@ -1212,13 +1218,34 @@ dl_main (const ElfW(Phdr) *phdr,
_dl_argc -= 2;
_dl_argv += 2;
}
+ else if (strcmp (_dl_argv[1], "--help") == 0)
+ {
+ state.mode = rtld_help;
+ --_dl_argc;
+ ++_dl_argv;
+ }
+ else if (_dl_argv[1][0] == '-' && _dl_argv[1][1] == '-')
+ {
+ if (_dl_argv[1][1] == '\0')
+ /* End of option list. */
+ break;
+ else
+ /* Unrecognized option. */
+ _dl_usage (argv0, _dl_argv[1]);
+ }
else
break;
/* If we have no further argument the program was called incorrectly.
Grant the user some education. */
if (_dl_argc < 2)
- _dl_usage ();
+ {
+ if (state.mode == rtld_help)
+ /* --help without an executable is not an error. */
+ _dl_help (argv0, &state);
+ else
+ _dl_usage (argv0, NULL);
+ }
++_dl_skip_args;
--_dl_argc;
@@ -1243,7 +1270,7 @@ dl_main (const ElfW(Phdr) *phdr,
break;
}
- if (__builtin_expect (state.mode, normal) == verify)
+ if (state.mode == verify || state.mode == rtld_help)
{
const char *objname;
const char *err_str = NULL;
@@ -1256,9 +1283,16 @@ dl_main (const ElfW(Phdr) *phdr,
(void) _dl_catch_error (&objname, &err_str, &malloced, map_doit,
&args);
if (__glibc_unlikely (err_str != NULL))
- /* We don't free the returned string, the programs stops
- anyway. */
- _exit (EXIT_FAILURE);
+ {
+ /* We don't free the returned string, the programs stops
+ anyway. */
+ if (state.mode == rtld_help)
+ /* Mask the failure to load the main object. The help
+ message contains less information in this case. */
+ _dl_help (argv0, &state);
+ else
+ _exit (EXIT_FAILURE);
+ }
}
else
{
@@ -1607,6 +1641,11 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT);
audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT);
+ /* At this point, all data has been obtained that is included in the
+ --help output. */
+ if (__builtin_expect (state.mode, normal) == rtld_help)
+ _dl_help (argv0, &state);
+
/* If we have auditing DSOs to load, do it now. */
bool need_security_init = true;
if (state.audit_list.length > 0)