diff mbox series

[v3] cpupower: Make help command available for custom install dir

Message ID 20240627-fix-help-issue-v3-1-85318a3974e4@gmail.com (mailing list archive)
State New
Delegated to: Shuah Khan
Headers show
Series [v3] cpupower: Make help command available for custom install dir | expand

Commit Message

Roman Storozhenko June 27, 2024, 7:49 a.m. UTC
When the 'cpupower' utility installed in the custom dir, it fails to
render appropriate help info for a particular subcommand:
$ LD_LIBRARY_PATH=lib64/ bin/cpupower help monitor
with error message like 'No manual entry for cpupower-monitor.1'
The issue is that under the hood it calls 'exec' function with
the following args: 'man cpupower-monitor.1'. In turn, 'man' search
path is defined in '/etc/manpath.config'. Of course it contains only
standard system man paths.
Make subcommands help available for a user by setting up 'MANPATH'
environment variable to the custom installation man pages dir. That
variable value will be prepended to the man pages standard search paths
as described in 'SEARCH PATH' section of MANPATH(5).

Signed-off-by: Roman Storozhenko <romeusmeister@gmail.com>
---
Changes in v3:
- fix: append the previous value of "MANPATH" to a new one instead of
  its replacement
- Link to v2: https://lore.kernel.org/r/20240622-fix-help-issue-v2-1-6c19e28a4ec1@gmail.com

Changes in v2:
- Fixed spelling errors
- Simplified man pages search approach by the 'MANPATH' variable usage
- Link to v1: https://lore.kernel.org/r/20240621-fix-help-issue-v1-1-7906998d46eb@gmail.com
---
 tools/power/cpupower/utils/cpupower.c | 43 ++++++++++++++++++++++++++++++-----
 1 file changed, 37 insertions(+), 6 deletions(-)


---
base-commit: 2102cb0d050d34d50b9642a3a50861787527e922
change-id: 20240619-fix-help-issue-573c40bb6427

Best regards,

Comments

Shuah Khan June 27, 2024, 5:33 p.m. UTC | #1
On 6/27/24 01:49, Roman Storozhenko wrote:
> When the 'cpupower' utility installed in the custom dir, it fails to
> render appropriate help info for a particular subcommand:
> $ LD_LIBRARY_PATH=lib64/ bin/cpupower help monitor
> with error message like 'No manual entry for cpupower-monitor.1'
> The issue is that under the hood it calls 'exec' function with
> the following args: 'man cpupower-monitor.1'. In turn, 'man' search
> path is defined in '/etc/manpath.config'. Of course it contains only
> standard system man paths.
> Make subcommands help available for a user by setting up 'MANPATH'
> environment variable to the custom installation man pages dir. That
> variable value will be prepended to the man pages standard search paths
> as described in 'SEARCH PATH' section of MANPATH(5).

What I am asking you is what happens when you set the MANPATH before
running the command?

thanks,
-- Shuah
Roman Storozhenko June 28, 2024, 11:30 a.m. UTC | #2
On Thu, Jun 27, 2024 at 7:33 PM Shuah Khan <skhan@linuxfoundation.org> wrote:
>
> On 6/27/24 01:49, Roman Storozhenko wrote:
> > When the 'cpupower' utility installed in the custom dir, it fails to
> > render appropriate help info for a particular subcommand:
> > $ LD_LIBRARY_PATH=lib64/ bin/cpupower help monitor
> > with error message like 'No manual entry for cpupower-monitor.1'
> > The issue is that under the hood it calls 'exec' function with
> > the following args: 'man cpupower-monitor.1'. In turn, 'man' search
> > path is defined in '/etc/manpath.config'. Of course it contains only
> > standard system man paths.
> > Make subcommands help available for a user by setting up 'MANPATH'
> > environment variable to the custom installation man pages dir. That
> > variable value will be prepended to the man pages standard search paths
> > as described in 'SEARCH PATH' section of MANPATH(5).
>
> What I am asking you is what happens when you set the MANPATH before
> running the command?

It adds the custom search path to the beginning of the MANPATH variable.
I tested this case. All works as expected.

>
> thanks,
> -- Shuah
Shuah Khan June 28, 2024, 7:45 p.m. UTC | #3
On 6/28/24 05:30, Roman Storozhenko wrote:
> On Thu, Jun 27, 2024 at 7:33 PM Shuah Khan <skhan@linuxfoundation.org> wrote:
>>
>> On 6/27/24 01:49, Roman Storozhenko wrote:
>>> When the 'cpupower' utility installed in the custom dir, it fails to
>>> render appropriate help info for a particular subcommand:
>>> $ LD_LIBRARY_PATH=lib64/ bin/cpupower help monitor
>>> with error message like 'No manual entry for cpupower-monitor.1'
>>> The issue is that under the hood it calls 'exec' function with
>>> the following args: 'man cpupower-monitor.1'. In turn, 'man' search
>>> path is defined in '/etc/manpath.config'. Of course it contains only
>>> standard system man paths.
>>> Make subcommands help available for a user by setting up 'MANPATH'
>>> environment variable to the custom installation man pages dir. That
>>> variable value will be prepended to the man pages standard search paths
>>> as described in 'SEARCH PATH' section of MANPATH(5).
>>
>> What I am asking you is what happens when you set the MANPATH before
>> running the command?
> 
> It adds the custom search path to the beginning of the MANPATH variable.
> I tested this case. All works as expected.
> 

Let's try again. What happens if you run the command with MANPATH set and
exported and then run the command. Can you send the output?

thanks,
-- Shuah
Roman Storozhenko June 29, 2024, 10:48 a.m. UTC | #4
On Fri, Jun 28, 2024 at 9:45 PM Shuah Khan <skhan@linuxfoundation.org> wrote:
>
> On 6/28/24 05:30, Roman Storozhenko wrote:
> > On Thu, Jun 27, 2024 at 7:33 PM Shuah Khan <skhan@linuxfoundation.org> wrote:
> >>
> >> On 6/27/24 01:49, Roman Storozhenko wrote:
> >>> When the 'cpupower' utility installed in the custom dir, it fails to
> >>> render appropriate help info for a particular subcommand:
> >>> $ LD_LIBRARY_PATH=lib64/ bin/cpupower help monitor
> >>> with error message like 'No manual entry for cpupower-monitor.1'
> >>> The issue is that under the hood it calls 'exec' function with
> >>> the following args: 'man cpupower-monitor.1'. In turn, 'man' search
> >>> path is defined in '/etc/manpath.config'. Of course it contains only
> >>> standard system man paths.
> >>> Make subcommands help available for a user by setting up 'MANPATH'
> >>> environment variable to the custom installation man pages dir. That
> >>> variable value will be prepended to the man pages standard search paths
> >>> as described in 'SEARCH PATH' section of MANPATH(5).
> >>
> >> What I am asking you is what happens when you set the MANPATH before
> >> running the command?
> >
> > It adds the custom search path to the beginning of the MANPATH variable.
> > I tested this case. All works as expected.
> >
>
> Let's try again. What happens if you run the command with MANPATH set and
> exported and then run the command. Can you send the output?

hedin@laptop:~/prj/cpupower/install/usr$ echo $MANPATH
/tmp/
hedin@laptop:~/prj/cpupower/install/usr$ LD_LIBRARY_PATH=lib64/
bin/cpupower help monitor
...................
man output
...................
hedin@laptop:~/prj/cpupower/install/usr$ echo $MANPATH
/tmp/
hedin@laptop:~/prj/cpupower/install/usr$

Just in case, the following is the output of the debugging session showing
how the 'MANPATH' looks like just before calling 'exec':

Breakpoint 2, print_man_page (subpage=0x7fffffffe1cb "monitor") at
utils/cpupower.c:84
84      {
(gdb) n
89              if (!subpage)
(gdb) n
93              subpage_len += strlen(subpage);
(gdb) n
95              page = malloc(subpage_len);
(gdb) n
96              if (!page)
(gdb) n
99              sprintf(page, "cpupower");
(gdb) n
100             if ((subpage != NULL) && strcmp(subpage, "help")) {
(gdb) n
101                     strcat(page, "-");
(gdb) n
102                     strcat(page, subpage);
(gdb) n
106             if (readlink("/proc/self/exe", exec_path, PATH_MAX) > 0) {
(gdb) n
107                     exec_dir = strdup(exec_path);
(gdb) n
108                     if (!exec_dir) {
(gdb) n
117                     man_env = getenv("MANPATH");
(gdb) n
118                     if (asprintf(&man_path, "%s/../man:%s",
(gdb) n
120                             setenv("MANPATH", man_path, 1);
(gdb) n
121                             free(exec_dir);
(gdb) p man_path
$1 = 0x55555556db20 "/home/hedin/prj/cpupower/install/usr/bin/../man:/tmp/"
(gdb) c
Continuing.
process 26122 is executing new program: /usr/bin/man


>
> thanks,
> -- Shuah
>
>
>
diff mbox series

Patch

diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
index 9ec973165af1..a7777e693fa7 100644
--- a/tools/power/cpupower/utils/cpupower.c
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -12,6 +12,8 @@ 
 #include <unistd.h>
 #include <errno.h>
 #include <sched.h>
+#include <libgen.h>
+#include <limits.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/utsname.h>
@@ -80,14 +82,17 @@  static void print_help(void)
 
 static int print_man_page(const char *subpage)
 {
-	int len;
-	char *page;
+	char *page, *man_path, *exec_dir, *man_env;
+	char exec_path[PATH_MAX];
+	int subpage_len;
 
-	len = 10; /* enough for "cpupower-" */
-	if (subpage != NULL)
-		len += strlen(subpage);
+	if (!subpage)
+		return -EINVAL;
 
-	page = malloc(len);
+	subpage_len = 10; /* enough for "cpupower-" */
+	subpage_len += strlen(subpage);
+
+	page = malloc(subpage_len);
 	if (!page)
 		return -ENOMEM;
 
@@ -97,6 +102,32 @@  static int print_man_page(const char *subpage)
 		strcat(page, subpage);
 	}
 
+	/* Get current process image name full path */
+	if (readlink("/proc/self/exe", exec_path, PATH_MAX) > 0) {
+		exec_dir = strdup(exec_path);
+		if (!exec_dir) {
+			free(page);
+			free(man_path);
+			return -ENOMEM;
+		}
+
+		/* Prepend standard search path for man pages with relative path
+		 * to custom install man directory
+		 */
+		man_env = getenv("MANPATH");
+		if (asprintf(&man_path, "%s/../man:%s",
+			dirname(exec_dir), (man_env ? man_env : "")) > 0) {
+			setenv("MANPATH", man_path, 1);
+			free(exec_dir);
+			free(man_path);
+		} else {
+			free(page);
+			free(exec_dir);
+			free(man_path);
+			return -ENOMEM;
+		}
+	}
+
 	execlp("man", "man", page, NULL);
 
 	/* should not be reached */