Hello,
The following command hangs:
$ ps -o user -p 1
Funnily enough, this works as expected:
$ ps -o user, -p 1
User
root
I took a look at the code:
1) with "-o user", the "fmt_string" variable is set to "user", and the
"posix_fmt" variable is set to 1 (see utils/ps.c):
case 'o': fmt_string = arg; posix_fmt = 1; break;
2) fmt_string is later overriden because "user" can be found in
"output_fmts". Its new value is "%^%user %pid %th %cpu %mem %sz %rss %tt
%sc %stat %start %time %command" (see utils/ps.c)
case ARGP_KEY_SUCCESS:
/* Select an explicit format string if FMT_STRING is a format
name. This is done here because parse_enum needs STATE. */
{
const char *fmt_name (unsigned n)
{
return
n >= (sizeof output_fmts / sizeof *output_fmts)
? 0
: output_fmts[n].name;
}
int fmt_index = parse_enum (fmt_string, fmt_name,
"format type", 1, state);
if (fmt_index >= 0)
{
fmt_string = output_fmts[fmt_index].fmt;
if (sort_key_name == NULL)
sort_key_name = output_fmts[fmt_index].sort_key;
}
}
3) We call psout(), which calls ps_fmt_create(), which calls
_fmt_create(). The first argument of _fmt_create, "src", is the long
string I pasted a few lines above. We never leave the
"while (*src != '\0')" loop, because we always end up here, without
having modified src (see libps/fmt.c):
else if (!isalnum (*src) && *src != '_')
/* This field spec doesn't have a name, so use its flags fields
to set the global ones, and skip it. */
{
global_clr_flags = clr_flags;
global_inv_flags = inv_flags;
continue;
}
It seems like the '%' character, which is found in "src", is only
treated in the non-posix code. Plus, since the "%^%pid %th %stat %sl
%pgins %pgflts %cowflts %zfills %sz %rss %cpu %mem %command" string
looks GNU-specific, I think that step 2 should only be done if the Posix
format is not used.
I attached a patch that fixes the issue, but I can't guarantee that it
doesn't break anything. What do you think ?
Regards,
Cyril Roelandt.
diff --git a/utils/ps.c b/utils/ps.c
index 992b467..1053b86 100644
--- a/utils/ps.c
+++ b/utils/ps.c
@@ -328,6 +328,8 @@ main(int argc, char *argv[])
/* Select an explicit format string if FMT_STRING is a format
name. This is done here because parse_enum needs STATE. */
{
+ if (posix_fmt)
+ break;
const char *fmt_name (unsigned n)
{
return