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

Reply via email to