|
|
b1dca6 |
commit e0f1a58f3d1f4f55591b524e9dcff23cc98a509e
|
|
|
b1dca6 |
Author: Florian Weimer <fweimer@redhat.com>
|
|
|
b1dca6 |
Date: Thu Oct 8 10:57:10 2020 +0200
|
|
|
b1dca6 |
|
|
|
b1dca6 |
elf: Implement ld.so --help
|
|
|
b1dca6 |
|
|
|
b1dca6 |
--help processing is deferred to the point where the executable has
|
|
|
b1dca6 |
been loaded, so that it is possible to eventually include information
|
|
|
b1dca6 |
from the main executable in the help output.
|
|
|
b1dca6 |
|
|
|
b1dca6 |
As suggested in the GNU command-line interface guidelines, the help
|
|
|
b1dca6 |
message is printed to standard output, and the exit status is
|
|
|
b1dca6 |
successful.
|
|
|
b1dca6 |
|
|
|
b1dca6 |
Handle usage errors closer to the GNU command-line interface
|
|
|
b1dca6 |
guidelines.
|
|
|
b1dca6 |
|
|
|
b1dca6 |
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
|
|
b1dca6 |
|
|
|
b1dca6 |
diff --git a/elf/dl-main.h b/elf/dl-main.h
|
|
|
b1dca6 |
index 79c9c40056504f80..ac7249a580214860 100644
|
|
|
b1dca6 |
--- a/elf/dl-main.h
|
|
|
b1dca6 |
+++ b/elf/dl-main.h
|
|
|
b1dca6 |
@@ -63,6 +63,7 @@ struct audit_list
|
|
|
b1dca6 |
enum rtld_mode
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace,
|
|
|
b1dca6 |
+ rtld_mode_help,
|
|
|
b1dca6 |
};
|
|
|
b1dca6 |
|
|
|
b1dca6 |
/* Aggregated state information extracted from environment variables
|
|
|
b1dca6 |
@@ -101,6 +102,11 @@ call_init_paths (const struct dl_main_state *state)
|
|
|
b1dca6 |
}
|
|
|
b1dca6 |
|
|
|
b1dca6 |
/* Print ld.so usage information and exit. */
|
|
|
b1dca6 |
-_Noreturn void _dl_usage (void) attribute_hidden;
|
|
|
b1dca6 |
+_Noreturn void _dl_usage (const char *argv0, const char *wrong_option)
|
|
|
b1dca6 |
+ attribute_hidden;
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
+/* Print ld.so --help output and exit. */
|
|
|
b1dca6 |
+_Noreturn void _dl_help (const char *argv0, struct dl_main_state *state)
|
|
|
b1dca6 |
+ attribute_hidden;
|
|
|
b1dca6 |
|
|
|
b1dca6 |
#endif /* _DL_MAIN */
|
|
|
b1dca6 |
diff --git a/elf/dl-usage.c b/elf/dl-usage.c
|
|
|
b1dca6 |
index f3d89d22b71d7d12..c1820dca2fa117ee 100644
|
|
|
b1dca6 |
--- a/elf/dl-usage.c
|
|
|
b1dca6 |
+++ b/elf/dl-usage.c
|
|
|
b1dca6 |
@@ -19,12 +19,24 @@
|
|
|
b1dca6 |
#include <dl-cache.h>
|
|
|
b1dca6 |
#include <dl-main.h>
|
|
|
b1dca6 |
#include <ldsodefs.h>
|
|
|
b1dca6 |
+#include <unistd.h>
|
|
|
b1dca6 |
|
|
|
b1dca6 |
void
|
|
|
b1dca6 |
-_dl_usage (void)
|
|
|
b1dca6 |
+_dl_usage (const char *argv0, const char *wrong_option)
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
- _dl_fatal_printf ("\
|
|
|
b1dca6 |
-Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
|
|
|
b1dca6 |
+ if (wrong_option != NULL)
|
|
|
b1dca6 |
+ _dl_error_printf ("%s: unrecognized option '%s'\n", argv0, wrong_option);
|
|
|
b1dca6 |
+ else
|
|
|
b1dca6 |
+ _dl_error_printf ("%s: missing program name\n", argv0);
|
|
|
b1dca6 |
+ _dl_error_printf ("Try '%s --help' for more information.\n", argv0);
|
|
|
b1dca6 |
+ _exit (EXIT_FAILURE);
|
|
|
b1dca6 |
+}
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
+void
|
|
|
b1dca6 |
+_dl_help (const char *argv0, struct dl_main_state *state)
|
|
|
b1dca6 |
+{
|
|
|
b1dca6 |
+ _dl_printf ("\
|
|
|
b1dca6 |
+Usage: %s [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
|
|
|
b1dca6 |
You have invoked `ld.so', the helper program for shared library executables.\n\
|
|
|
b1dca6 |
This program usually lives in the file `/lib/ld.so', and special directives\n\
|
|
|
b1dca6 |
in executable files using ELF shared libraries tell the system's program\n\
|
|
|
b1dca6 |
@@ -47,5 +59,9 @@ of this helper program; chances are you did not intend to run this program.\n\
|
|
|
b1dca6 |
in LIST\n\
|
|
|
b1dca6 |
--audit LIST use objects named in LIST as auditors\n\
|
|
|
b1dca6 |
--preload LIST preload objects named in LIST\n\
|
|
|
b1dca6 |
- --argv0 STRING set argv[0] to STRING before running\n");
|
|
|
b1dca6 |
+ --argv0 STRING set argv[0] to STRING before running\n\
|
|
|
b1dca6 |
+ --help display this help and exit\n\
|
|
|
b1dca6 |
+",
|
|
|
b1dca6 |
+ argv0);
|
|
|
b1dca6 |
+ _exit (EXIT_SUCCESS);
|
|
|
b1dca6 |
}
|
|
|
b1dca6 |
diff --git a/elf/rtld.c b/elf/rtld.c
|
|
|
b1dca6 |
index 8e91cee41b62b894..b92641cb1c2d99a6 100644
|
|
|
b1dca6 |
--- a/elf/rtld.c
|
|
|
b1dca6 |
+++ b/elf/rtld.c
|
|
|
b1dca6 |
@@ -1145,6 +1145,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
|
b1dca6 |
/* Set up a flag which tells we are just starting. */
|
|
|
b1dca6 |
_dl_starting_up = 1;
|
|
|
b1dca6 |
|
|
|
b1dca6 |
+ const char *ld_so_name = _dl_argv[0];
|
|
|
b1dca6 |
if (*user_entry == (ElfW(Addr)) ENTRY_POINT)
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
/* Ho ho. We are not the program interpreter! We are the program
|
|
|
b1dca6 |
@@ -1172,8 +1173,12 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
|
b1dca6 |
while (_dl_argc > 1)
|
|
|
b1dca6 |
if (! strcmp (_dl_argv[1], "--list"))
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
- state.mode = rtld_mode_list;
|
|
|
b1dca6 |
- GLRO(dl_lazy) = -1; /* This means do no dependency analysis. */
|
|
|
b1dca6 |
+ if (state.mode != rtld_mode_help)
|
|
|
b1dca6 |
+ {
|
|
|
b1dca6 |
+ state.mode = rtld_mode_list;
|
|
|
b1dca6 |
+ /* This means do no dependency analysis. */
|
|
|
b1dca6 |
+ GLRO(dl_lazy) = -1;
|
|
|
b1dca6 |
+ }
|
|
|
b1dca6 |
|
|
|
b1dca6 |
++_dl_skip_args;
|
|
|
b1dca6 |
--_dl_argc;
|
|
|
b1dca6 |
@@ -1181,7 +1186,8 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
|
b1dca6 |
}
|
|
|
b1dca6 |
else if (! strcmp (_dl_argv[1], "--verify"))
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
- state.mode = rtld_mode_verify;
|
|
|
b1dca6 |
+ if (state.mode != rtld_mode_help)
|
|
|
b1dca6 |
+ state.mode = rtld_mode_verify;
|
|
|
b1dca6 |
|
|
|
b1dca6 |
++_dl_skip_args;
|
|
|
b1dca6 |
--_dl_argc;
|
|
|
b1dca6 |
@@ -1236,13 +1242,34 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
|
b1dca6 |
_dl_argc -= 2;
|
|
|
b1dca6 |
_dl_argv += 2;
|
|
|
b1dca6 |
}
|
|
|
b1dca6 |
+ else if (strcmp (_dl_argv[1], "--help") == 0)
|
|
|
b1dca6 |
+ {
|
|
|
b1dca6 |
+ state.mode = rtld_mode_help;
|
|
|
b1dca6 |
+ --_dl_argc;
|
|
|
b1dca6 |
+ ++_dl_argv;
|
|
|
b1dca6 |
+ }
|
|
|
b1dca6 |
+ else if (_dl_argv[1][0] == '-' && _dl_argv[1][1] == '-')
|
|
|
b1dca6 |
+ {
|
|
|
b1dca6 |
+ if (_dl_argv[1][1] == '\0')
|
|
|
b1dca6 |
+ /* End of option list. */
|
|
|
b1dca6 |
+ break;
|
|
|
b1dca6 |
+ else
|
|
|
b1dca6 |
+ /* Unrecognized option. */
|
|
|
b1dca6 |
+ _dl_usage (ld_so_name, _dl_argv[1]);
|
|
|
b1dca6 |
+ }
|
|
|
b1dca6 |
else
|
|
|
b1dca6 |
break;
|
|
|
b1dca6 |
|
|
|
b1dca6 |
/* If we have no further argument the program was called incorrectly.
|
|
|
b1dca6 |
Grant the user some education. */
|
|
|
b1dca6 |
if (_dl_argc < 2)
|
|
|
b1dca6 |
- _dl_usage ();
|
|
|
b1dca6 |
+ {
|
|
|
b1dca6 |
+ if (state.mode == rtld_mode_help)
|
|
|
b1dca6 |
+ /* --help without an executable is not an error. */
|
|
|
b1dca6 |
+ _dl_help (ld_so_name, &state);
|
|
|
b1dca6 |
+ else
|
|
|
b1dca6 |
+ _dl_usage (ld_so_name, NULL);
|
|
|
b1dca6 |
+ }
|
|
|
b1dca6 |
|
|
|
b1dca6 |
++_dl_skip_args;
|
|
|
b1dca6 |
--_dl_argc;
|
|
|
b1dca6 |
@@ -1267,7 +1294,8 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
|
b1dca6 |
break;
|
|
|
b1dca6 |
}
|
|
|
b1dca6 |
|
|
|
b1dca6 |
- if (__glibc_unlikely (state.mode == rtld_mode_verify))
|
|
|
b1dca6 |
+ if (__glibc_unlikely (state.mode == rtld_mode_verify
|
|
|
b1dca6 |
+ || state.mode == rtld_mode_help))
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
const char *objname;
|
|
|
b1dca6 |
const char *err_str = NULL;
|
|
|
b1dca6 |
@@ -1280,9 +1308,16 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
|
b1dca6 |
(void) _dl_catch_error (&objname, &err_str, &malloced, map_doit,
|
|
|
b1dca6 |
&args);
|
|
|
b1dca6 |
if (__glibc_unlikely (err_str != NULL))
|
|
|
b1dca6 |
- /* We don't free the returned string, the programs stops
|
|
|
b1dca6 |
- anyway. */
|
|
|
b1dca6 |
- _exit (EXIT_FAILURE);
|
|
|
b1dca6 |
+ {
|
|
|
b1dca6 |
+ /* We don't free the returned string, the programs stops
|
|
|
b1dca6 |
+ anyway. */
|
|
|
b1dca6 |
+ if (state.mode == rtld_mode_help)
|
|
|
b1dca6 |
+ /* Mask the failure to load the main object. The help
|
|
|
b1dca6 |
+ message contains less information in this case. */
|
|
|
b1dca6 |
+ _dl_help (ld_so_name, &state);
|
|
|
b1dca6 |
+ else
|
|
|
b1dca6 |
+ _exit (EXIT_FAILURE);
|
|
|
b1dca6 |
+ }
|
|
|
b1dca6 |
}
|
|
|
b1dca6 |
else
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
@@ -1632,6 +1667,11 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
|
|
|
b1dca6 |
audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT);
|
|
|
b1dca6 |
audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT);
|
|
|
b1dca6 |
|
|
|
b1dca6 |
+ /* At this point, all data has been obtained that is included in the
|
|
|
b1dca6 |
+ --help output. */
|
|
|
b1dca6 |
+ if (__glibc_unlikely (state.mode == rtld_mode_help))
|
|
|
b1dca6 |
+ _dl_help (ld_so_name, &state);
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
/* If we have auditing DSOs to load, do it now. */
|
|
|
b1dca6 |
bool need_security_init = true;
|
|
|
b1dca6 |
if (state.audit_list.length > 0)
|