Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed the return value of getCommandLine() method of linuxOSProcess and macOSProcess from null-delimited string to space-delimited string #1729

Merged
merged 7 commits into from
Oct 2, 2021

Conversation

prathamgandhi
Copy link
Contributor

This is a fix to the third issue mentioned in #1723. The OSProcess javadoc and UPGRADING.md have been fixed as required.

The return value of getCommandLine() method of macOSProcess and
linuxOSProcess have been changed from a null-delimited string to a
space-delimited string.
Copy link
Member

@dbwiddis dbwiddis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this PR. A few comments inline -- since we're using memoizers to only fetch the information once the processing should be done in the memoized query method.

@@ -133,7 +135,7 @@ public String getPath() {

@Override
public String getCommandLine() {
return this.commandLine.get();
return Arrays.stream(commandLine.get().split("\0")).collect(Collectors.joining(" "));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this approach was appropriate for Linux, you can look at the queryCommandLine() method and see it simply joins getArguments() using the null. So It's better to just join with a space in that method, and then you could return it directly here without further processing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All right, I've fixed it and understood how it improves performance. Could you maybe explain in brief why linux and mac do this differently? Like what section makes it platform-dependent and if it improves performance in both the cases, just for learning's sake.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linux provides the command line arguments via a null-delimited string in the proc filesystem, specifically /proc/[pid]/cmdline. (See man proc.)

macOS provides the command line arguments via sysctl call (KERN_PROCARGS2) in a null-delimited buffer. We can iterate that buffer to fetch the strings.

Before we (recently) added methods to fetch the process arguments separately, and because of the native null-delimited strings, these two OS's provided the ability to parse the arguments without having to do special treatment of spaces in names, etc. Rather than "lose information" by replacing the nulls with spaces, we provided users the full null-delimited string to parse to get the argument list themselves.

For the rest of the Unix-based implementations we just fetched the space-delimited argument string from the ps output (which is truncated to 80 characters on Solaris), and we got a space-delimited string from Windows via WMI (with additional parsing complexities using quotation marks). Parsing space-delimited command lines is not trivial, and rather than try to parse all these to a list we just returned them as-is to the user and let them do the parsing.

With the addition of a separate list of command line arguments, user-level parsing of getCommandLine() is no longer necessary, so the goal of this fix was just to simplify the getCommandLine output to the same common "user readable" space-delimited output on all OS's. Users who wanted to simply display a user-readable string had to do special cases for macOS and Linux to process the nulls. They will no longer have to do so.

There is still some bit of platform dependence in the output. While all the other Unix implementations now combine the argument list, that approach fails if you're not running with elevated permissions and querying a process you don't own. For those cases, the ps-based parsing does still work (since ps is owned by root) and is provided as a "backup" option (so for example on Solaris not running elevated, you'll get a truncated 80-character output for some processes and full output on others that you own). Bottom line: the method should now be treated only as a cosmetic "best effort output" and anyone looking to actually parse the output should use getArguments().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohhh, I understand now. Thanks for the explanation and all the help. Learnt a lot from this.

oshi-core/src/main/java/oshi/software/os/OSProcess.java Outdated Show resolved Hide resolved
@coveralls
Copy link

Coverage Status

Coverage remained the same at 88.023% when pulling 4ceb58f on prathamgandhi:master into e081d02 on oshi:master.

@dbwiddis dbwiddis merged commit e0e1a25 into oshi:master Oct 2, 2021
@dbwiddis dbwiddis added the hacktoberfest-accepted Accepted during Hacktoberfest label Oct 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hacktoberfest-accepted Accepted during Hacktoberfest
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants