示例#1
0
/************************* parse BSD options **********************/
static const char *parse_bsd_option(void){
  const char *arg;
  const char *err;

  flagptr = ps_argv[thisarg];  /* assume we _have_ a '-' */
  if(flagptr[0]=='-'){
    if(!force_bsd) return "Can't happen!  Problem #1.";
  }else{
    flagptr--; /* off beginning, will increment before use */
    if(personality & PER_FORCE_BSD){
      if(!force_bsd) return "Can't happen!  Problem #2.";
    }else{
      if(force_bsd) return "2nd chance parse failed, not BSD or SysV.";
    }
  }

  while(*++flagptr){
    switch(*flagptr){
    case '0' ... '9': /* end */
      trace("0..9  Old BSD-style select by process ID\n");
      arg=flagptr;
      err=parse_list(arg, parse_pid);
      if(err) return err;
      selection_list->typecode = SEL_PID;
      return NULL; /* can't have any more options */
#if 0
    case 'A':
      /* maybe this just does a larger malloc() ? */
      trace("A Increases the argument space (Digital Unix)\n");
      return "Option A is reserved.";
      break;
    case 'C':
      /* should divide result by 1-(e**(foo*log(bar))) */
      trace("C Use raw CPU time for %%CPU instead of decaying ave\n");
      return "Option C is reserved.";
      break;
#endif
    case 'L': /* single */
      trace("L List all format specifiers\n");
      exclusive("L");
      print_format_specifiers();
      exit(0);
#if 0
    case 'M':
      trace("M junk (use alternate core)\n");
      return "Option M is unsupported, try N or -n instead.";
      break;
#endif
    case 'N': /* end */
      trace("N Specify namelist file\n");
      arg=get_opt_arg();
      if(!arg) return "Alternate System.map file must follow N.";
      namelist_file = arg;
      return NULL; /* can't have any more options */
    case 'O': /* end */
      trace("O Like o + defaults, add new columns after PID. Also sort.\n");
      arg=get_opt_arg();
      if(!arg) return "Format or sort specification must follow O.";
      defer_sf_option(arg, SF_B_O);
      return NULL; /* can't have any more options */
      break;
    case 'S':
      trace("S include dead kids in sum\n");
      include_dead_children = 1;
      break;
    case 'T':
      trace("T Select all processes on this terminal\n");
      /* put our tty on a tiny list */
      {
        selection_node *node;
        node = malloc(sizeof(selection_node));
        node->u = malloc(sizeof(sel_union));
        node->u[0].tty = cached_tty;
        node->typecode = SEL_TTY;
        node->n = 1;
        node->next = selection_list;
        selection_list = node;
      }
      break;
    case 'U': /* end */
      trace("U Select processes for specified users.\n");
      arg=get_opt_arg();
      if(!arg) return "List of users must follow U.";
      err=parse_list(arg, parse_uid);
      if(err) return err;
      selection_list->typecode = SEL_EUID;
      return NULL; /* can't have any more options */
    case 'V': /* single */
      trace("V show version info\n");
      exclusive("V");
      display_version();
      exit(0);
    case 'W':
      trace("W N/A get swap info from ... not /dev/drum.\n");
      return "Obsolete W option not supported. (You have a /dev/drum?)";
      break;
    case 'X':
      trace("X Old Linux i386 register format\n");
      format_flags |= FF_LX;
      break;
    case 'a':
      trace("a Select all w/tty, including other users\n");
      simple_select |= SS_B_a;
      break;
    case 'c':
      trace("c true command name\n");
      bsd_c_option = 1;
      break;
    case 'e':
      trace("e environment\n");
      bsd_e_option = 1;
      break;
    case 'f':
      trace("f ASCII art forest\n");
      forest_type = 'b';
      break;
    case 'g':
      trace("g _all_, even group leaders!.\n");
      simple_select |= SS_B_g;
      break;
    case 'h':
      trace("h Repeat header... yow.\n");
      if(header_type) return "Only one heading option may be specified.";
      if(personality & PER_BSD_h) header_type = HEAD_MULTI;
      else                        header_type = HEAD_NONE;
      break;
    case 'j':
      trace("j job control format\n");
      format_flags |= FF_Bj;
      break;
#if 0
    case 'k':
      trace("k N/A Use /vmcore as c-dumpfile\n");
      return "Obsolete k option not supported.";
      break;
#endif
    case 'l':
      trace("l Display long format\n");
      format_flags |= FF_Bl;
      break;
    case 'm':
      trace("m all threads, sort on mem use, show mem info\n");
      if(personality & PER_OLD_m){
        format_flags |= FF_Lm;
        break;
      }
      if(personality & PER_BSD_m){
        defer_sf_option("pmem", SF_B_m);
        break;
      }
      /* not implemented -- silently ignore the option */
      break;
    case 'n':
      trace("n Numeric output for WCHAN, and USER replaced by UID\n");
      wchan_is_number = 1;
      user_is_number = 1;
      /* TODO add tty_is_number too? */
      break;
    case 'o': /* end */
      trace("o Specify user-defined format\n");
      arg=get_opt_arg();
      if(!arg) return "Format specification must follow o.";
      defer_sf_option(arg, SF_B_o);
      return NULL; /* can't have any more options */
    case 'p': /* end */
      trace("p Select by process ID\n");
      arg=get_opt_arg();
      if(!arg) return "List of process IDs must follow p.";
      err=parse_list(arg, parse_pid);
      if(err) return err;
      selection_list->typecode = SEL_PID;
      return NULL; /* can't have any more options */
    case 'r':
      trace("r Select running processes\n");
      running_only = 1;
      break;
    case 's':
      trace("s Display signal format\n");
      format_flags |= FF_Bs;
      break;
    case 't': /* end */
      trace("t Select by tty.\n");
      /* List of terminals (tty, pty...) _should_ follow t. */
      arg=get_opt_arg();
      if(!arg){
        /* Wow, obsolete BSD syntax. Put our tty on a tiny list. */
        selection_node *node;
        node = malloc(sizeof(selection_node));
        node->u = malloc(sizeof(sel_union));
        node->u[0].tty = cached_tty;
        node->typecode = SEL_TTY;
        node->n = 1;
        node->next = selection_list;
        selection_list = node;
        return NULL;
      }
      err=parse_list(arg, parse_tty);
      if(err) return err;
      selection_list->typecode = SEL_TTY;
      return NULL; /* can't have any more options */
    case 'u':
      trace("u Display user-oriented\n");
      format_flags |= FF_Bu;
      break;
    case 'v':
      trace("v Display virtual memory\n");
      format_flags |= FF_Bv;
      break;
    case 'w':
      trace("w wide output\n");
      w_count++;
      break;
    case 'x':
      trace("x Select processes without controlling ttys\n");
      simple_select |= SS_B_x;
      break;
    case '-':
      return "Embedded '-' among BSD options makes no sense.";
      break;
    case '\0':
      return "Please report the \"BSD \\0 can't happen\" bug.";
      break;
    default:
      return "Unsupported option (BSD syntax)";
    } /* switch */
  } /* while */
  return NULL;
}
示例#2
0
文件: parser.c 项目: DrinkShot/procps
/************************* parse BSD options **********************/
static const char *parse_bsd_option(void){
  const char *arg;
  const char *err;

  flagptr = ps_argv[thisarg];  /* assume we _have_ a '-' */
  if(flagptr[0]=='-'){
    if(!force_bsd) return _("cannot happen - problem #1");
  }else{
    flagptr--; /* off beginning, will increment before use */
    if(personality & PER_FORCE_BSD){
      if(!force_bsd) return _("cannot happen - problem #2");
    }else{
      if(force_bsd) return _("second chance parse failed, not BSD or SysV");
    }
  }

  while(*++flagptr){
    switch(*flagptr){
    case '0' ... '9': /* end */
      trace("0..9  pld BSD-style select by process ID\n");
      arg=flagptr;
      err=parse_list(arg, parse_pid);
      if(err) return err;
      selection_list->typecode = SEL_PID;
      return NULL; /* can't have any more options */
#if 0
    case 'A':
      /* maybe this just does a larger malloc() ? */
      trace("A increases the argument space (Digital Unix)\n");
      return _("option A is reserved");
      break;
    case 'C':
      /* should divide result by 1-(e**(foo*log(bar))) */
      trace("C use raw CPU time for %%CPU instead of decaying ave\n");
      return _("option C is reserved");
      break;
#endif
    case 'H':    // The FreeBSD way (NetBSD:s OpenBSD:k FreeBSD:H  -- NIH???)
      trace("H print LWP (thread) info\n");   // was: Use /vmcore as c-dumpfile\n");
      thread_flags |= TF_B_H;
      //format_modifiers |= FM_L;    // FIXME: determine if we need something like this
      break;
    case 'L': /* single */
      trace("L list all format specifiers\n");
      exclusive("L");
      print_format_specifiers();
      exit(0);
    case 'M':   // undocumented for now: these are proliferating!
      trace("M MacOS X thread display, like AIX/Tru64\n");
      thread_flags |= TF_B_m;
      break;
    case 'N': /* end */
      trace("N specify namelist file\n");
      arg=get_opt_arg();
      if(!arg) return _("alternate System.map file must follow N");
      namelist_file = arg;
      return NULL; /* can't have any more options */
    case 'O': /* end */
      trace("O like o + defaults, add new columns after PID, also sort\n");
      arg=get_opt_arg();
      if(!arg) return _("format or sort specification must follow O");
      defer_sf_option(arg, SF_B_O);
      return NULL; /* can't have any more options */
      break;
    case 'S':
      trace("S include dead kids in sum\n");
      include_dead_children = 1;
      break;
    case 'T':
      trace("T select all processes on this terminal\n");
      /* put our tty on a tiny list */
      {
        selection_node *node;
        node = malloc(sizeof(selection_node));
        node->u = malloc(sizeof(sel_union));
        node->u[0].tty = cached_tty;
        node->typecode = SEL_TTY;
        node->n = 1;
        node->next = selection_list;
        selection_list = node;
      }
      break;
    case 'U': /* end */
      trace("U select processes for specified users\n");
      arg=get_opt_arg();
      if(!arg) return _("list of users must follow U");
      err=parse_list(arg, parse_uid);
      if(err) return err;
      selection_list->typecode = SEL_EUID;
      return NULL; /* can't have any more options */
    case 'V': /* single */
      trace("V show version info\n");
      exclusive("V");
      display_version();
      exit(0);
    case 'W':
      trace("W N/A get swap info from ... not /dev/drum.\n");
      return _("obsolete W option not supported (you have a /dev/drum?)");
      break;
    case 'X':
      trace("X old Linux i386 register format\n");
      format_flags |= FF_LX;
      break;
    case 'Z':  /* FreeBSD does MAC like SGI's Irix does it */
      trace("Z print security label for Mandatory Access Control.\n");
      format_modifiers |= FM_M;
      break;
    case 'a':
      trace("a select all w/tty, including other users\n");
      simple_select |= SS_B_a;
      break;
    case 'c':
      trace("c true command name\n");
      bsd_c_option = 1;
      break;
//  case 'd':
//    trace("d FreeBSD-style tree\n");
//    forest_type = 'f';
//    break;
    case 'e':
      trace("e environment\n");
      bsd_e_option = 1;
      break;
    case 'f':
      trace("f ASCII art forest\n");
      forest_type = 'b';
      break;
    case 'g':
      trace("g _all_, even group leaders\n");
      simple_select |= SS_B_g;
      break;
    case 'h':
      trace("h repeat header\n");
      if(header_type) return _("only one heading option may be specified");
      if(personality & PER_BSD_h) header_type = HEAD_MULTI;
      else                        header_type = HEAD_NONE;
      break;
    case 'j':
      trace("j job control format\n");
      format_flags |= FF_Bj;
      break;
    case 'k':
      // OpenBSD: don't hide "kernel threads" -- like the swapper?
      // trace("k Print LWP (thread) info.\n");   // was: Use /vmcore as c-dumpfile\n");

      // NetBSD, and soon (?) FreeBSD: sort-by-keyword
      trace("k specify sorting keywords\n");
      arg=get_opt_arg();
      if(!arg) return _("long sort specification must follow 'k'");
      defer_sf_option(arg, SF_G_sort);
      return NULL; /* can't have any more options */
    case 'l':
      trace("l display long format\n");
      format_flags |= FF_Bl;
      break;
    case 'm':
      trace("m all threads, sort on mem use, show mem info\n");
      if(personality & PER_OLD_m){
        format_flags |= FF_Lm;
        break;
      }
      if(personality & PER_BSD_m){
        defer_sf_option("pmem", SF_B_m);
        break;
      }
      thread_flags |= TF_B_m;
      break;
    case 'n':
      trace("n numeric output for WCHAN, and USER replaced by UID\n");
      wchan_is_number = 1;
      user_is_number = 1;
      /* TODO add tty_is_number too? */
      break;
    case 'o': /* end */
      trace("o specify user-defined format\n");
      arg=get_opt_arg();
      if(!arg) return _("format specification must follow o");
      defer_sf_option(arg, SF_B_o);
      return NULL; /* can't have any more options */
    case 'p': /* end */
      trace("p select by process ID\n");
      arg=get_opt_arg();
      if(!arg) return _("list of process IDs must follow p");
      err=parse_list(arg, parse_pid);
      if(err) return err;
      selection_list->typecode = SEL_PID;
      return NULL; /* can't have any more options */
    case 'r':
      trace("r select running processes\n");
      running_only = 1;
      break;
    case 's':
      trace("s display signal format\n");
      format_flags |= FF_Bs;
      break;
    case 't': /* end */
      trace("t select by tty\n");
      /* List of terminals (tty, pty...) _should_ follow t. */
      arg=get_opt_arg();
      if(!arg){
        /* Wow, obsolete BSD syntax. Put our tty on a tiny list. */
        selection_node *node;
        node = malloc(sizeof(selection_node));
        node->u = malloc(sizeof(sel_union));
        node->u[0].tty = cached_tty;
        node->typecode = SEL_TTY;
        node->n = 1;
        node->next = selection_list;
        selection_list = node;
        return NULL;
      }
      err=parse_list(arg, parse_tty);
      if(err) return err;
      selection_list->typecode = SEL_TTY;
      return NULL; /* can't have any more options */
    case 'u':
      trace("u display user-oriented\n");
      format_flags |= FF_Bu;
      break;
    case 'v':
      trace("v display virtual memory\n");
      format_flags |= FF_Bv;
      break;
    case 'w':
      trace("w wide output\n");
      w_count++;
      break;
    case 'x':
      trace("x select processes without controlling ttys\n");
      simple_select |= SS_B_x;
      break;
    case '-':
      return _("embedded '-' among BSD options makes no sense");
      break;
    case '\0':
      catastrophic_failure(__FILE__, __LINE__, _("please report this bug"));
      break;
    default:
      return _("unsupported option (BSD syntax)");
    } /* switch */
  } /* while */
  return NULL;
}
示例#3
0
/***************** parse SysV options, including Unix98  *****************/
static const char *parse_sysv_option(void){
  const char *arg;
  const char *err;
  flagptr = ps_argv[thisarg];
  while(*++flagptr){
    /* Find any excuse to ignore stupid Unix98 misfeatures. */
    if(!strchr("aAdefgGlnoptuU", *flagptr)) not_pure_unix = 1;
    switch(*flagptr){
    case 'A':
      trace("-A selects all processes.\n");
      all_processes = 1;
      break;
    case 'C': /* end */
      trace("-C select by process name.\n");  /* Why only HP/UX and us? */
      arg=get_opt_arg();
      if(!arg) return "List of command names must follow -C.";
      err=parse_list(arg, parse_cmd);
      if(err) return err;
      selection_list->typecode = SEL_COMM;
      return NULL; /* can't have any more options */
    case 'F':  /* DYNIX/ptx -f plus sz,rss,psr=ENG between c and stime */
      trace("-F does fuller listing\n");
      format_modifiers |= FM_F;
      format_flags |= FF_Uf;
      unix_f_option = 1; /* does this matter? */
      break;
    case 'G': /* end */
      trace("-G select by RGID (supports names)\n");
      arg=get_opt_arg();
      if(!arg) return "List of real groups must follow -G.";
      err=parse_list(arg, parse_gid);
      if(err) return err;
      selection_list->typecode = SEL_RGID;
      return NULL; /* can't have any more options */
    case 'H':     /* another nice HP/UX feature */
      trace("-H Process heirarchy (like ASCII art forest option)\n");
      forest_type = 'u';
      break;
    case 'L':  /*  */
      /* In spite of the insane 2-level thread system, Sun appears to
       * have made this option Linux-compatible. If a process has N
       * threads, ps will produce N lines of output. (not N+1 lines)
       * Zombies are the only exception, with NLWP==0 and 1 output line.
       * SCO UnixWare uses -L too.
       */
      trace("-L Print LWP (thread) info.\n");
      format_modifiers |= FM_L;
      break;
    case 'M':  /* someday, maybe, we will have MAC like SGI's Irix */
      trace("-M Print security label for Mandatory Access Control.\n");
      format_modifiers |= FM_M;
      return "Sorry, no Mandatory Access Control support.";
      break;
    case 'N':
      trace("-N negates.\n");
      negate_selection = 1;
      break;
    case 'O': /* end */
      trace("-O is preloaded -o.\n");
      arg=get_opt_arg();
      if(!arg) return "Format or sort specification must follow -O.";
      defer_sf_option(arg, SF_U_O);
      return NULL; /* can't have any more options */
    case 'P':     /* SunOS 5 "psr" or unknown HP/UX feature */
      trace("-P adds columns of PRM info (HP) or PSR column (Sun)\n");
      format_modifiers |= FM_P;
      break;
#ifdef WE_UNDERSTAND_THIS
    case 'R':     /* unknown HP/UX feature */
      trace("-R selects PRM groups\n");
      return "Don't understand PRM on Linux.";
      break;
#endif
    case 'T':
      /* IRIX 6.5 docs suggest POSIX threads get shown individually.
       * This would make -T be like -L, -m, and m. (but an extra column)
       * Testing (w/ normal processes) shows 1 line/process, not 2.
       * Also, testing shows PID==SPID for all normal processes.
       */
      trace("-T adds strange SPID column (old sproc() threads?)\n");
      format_modifiers |= FM_T;
      break;
    case 'U': /* end */
      trace("-U select by RUID (supports names).\n");
      arg=get_opt_arg();
      if(!arg) return "List of real groups must follow -U.";
      err=parse_list(arg, parse_uid);
      if(err) return err;
      selection_list->typecode = SEL_RUID;
      return NULL; /* can't have any more options */
    case 'V': /* single */
      trace("-V prints version.\n");
      exclusive("-V");
      display_version();
      exit(0);
    case 'Z':     /* full Mandatory Access Control level info */
      trace("-Z shows full MAC info\n");
      return "Don't understand MAC on Linux.";
      break;
    case 'a':
      trace("-a select all with a tty, but omit session leaders.\n");
      simple_select |= SS_U_a;
      break;
    case 'c':
      /* HP-UX and SunOS 5 scheduling info modifier */
      trace("-c changes scheduling info.\n");
      format_modifiers |= FM_c;
      break;
    case 'd':
      trace("-d select all, but omit session leaders.\n");
      simple_select |= SS_U_d;
      break;
    case 'e':
      trace("-e selects all processes.\n");
      all_processes = 1;
      break;
    case 'f':
      trace("-f does full listing\n");
      format_flags |= FF_Uf;
      unix_f_option = 1; /* does this matter? */
      break;
    case 'g': /* end */
      trace("-g selects by session leader OR by group name\n");
      arg=get_opt_arg();
      if(!arg) return "List of session leaders OR effective group names must follow -g.";
      err=parse_list(arg, parse_pid);
      if(!err){
        selection_list->typecode = SEL_SESS;
        return NULL; /* can't have any more options */
      }
      err=parse_list(arg, parse_gid);
      if(!err){
        selection_list->typecode = SEL_EGID;
        return NULL; /* can't have any more options */
      }
      return "List of session leaders OR effective group IDs was invalid.";
    case 'j':
      trace("-j jobs format.\n");
      /* Debian uses RD_j and Digital uses JFMT */
      if(sysv_j_format) format_flags |= FF_Uj;
      else format_modifiers |= FM_j;
      break;
    case 'l':
      trace("-l long format.\n");
      format_flags |= FF_Ul;
      break;
    case 'm':
      trace("-m shows threads.\n");
      /* note that AIX shows 2 lines for a normal process */
      /* not implemented -- silently ignore the option */
      break;
    case 'n': /* end */
      trace("-n sets namelist file.\n");
      arg=get_opt_arg();
      if(!arg) return "Alternate System.map file must follow -n.";
      namelist_file = arg;
      return NULL; /* can't have any more options */
    case 'o': /* end */
      /* Unix98 has gross behavior regarding this. From the following: */
      /*            ps -o pid,nice=NICE,tty=TERMINAL,comm              */
      /* The result must be 2 columns: "PID NICE,tty=TERMINAL,comm"    */
      /* Yes, the second column has the name "NICE,tty=TERMINAL,comm"  */
      /* This parser looks for any excuse to ignore that braindamage.  */
      trace("-o user-defined format.\n");
      arg=get_opt_arg();
      if(!arg) return "Format specification must follow -o.";
      not_pure_unix |= defer_sf_option(arg, SF_U_o);
      return NULL; /* can't have any more options */
    case 'p': /* end */
      trace("-p select by PID.\n");
      arg=get_opt_arg();
      if(!arg) return "List of process IDs must follow -p.";
      err=parse_list(arg, parse_pid);
      if(err) return err;
      selection_list->typecode = SEL_PID;
      return NULL; /* can't have any more options */
#ifdef KNOW_WHAT_TO_DO_WITH_THIS
    case 'r':
      trace("-r some Digital Unix thing about warnings...\n");
      trace("   or SCO's option to chroot() for new /proc and /dev.\n");
      return "The -r option is reserved.";
      break;
#endif
    case 's': /* end */
      trace("-s Select processes belonging to the sessions given.\n");
      arg=get_opt_arg();
      if(!arg) return "List of session IDs must follow -s.";
      err=parse_list(arg, parse_pid);
      if(err) return err;
      selection_list->typecode = SEL_SESS;
      return NULL; /* can't have any more options */
    case 't': /* end */
      trace("-t select by tty.\n");
      arg=get_opt_arg();
      if(!arg) return "List of terminals (pty, tty...) must follow -t.";
      err=parse_list(arg, parse_tty);
      if(err) return err;
      selection_list->typecode = SEL_TTY;
      return NULL; /* can't have any more options */
    case 'u': /* end */
      trace("-u select by user ID (the EUID?) (supports names).\n");
      arg=get_opt_arg();
      if(!arg) return "List of users must follow -u.";
      err=parse_list(arg, parse_uid);
      if(err) return err;
      selection_list->typecode = SEL_EUID;
      return NULL; /* can't have any more options */
    case 'w':
      trace("-w wide output.\n");
      w_count++;
      break;
#ifdef NOBODY_HAS_BSD_HABITS_ANYMORE
    case 'x':     /* Same as -y, but for System V Release 4 MP */
      trace("-x works like Sun Solaris & SCO Unixware -y option\n");
      format_modifiers |= FM_x;
      break;
#endif
    case 'y':  /* Sun's -l hack (also: Irix "lnode" resource control info) */
      trace("-y Print lnone info in UID/USER column or do Sun -l hack.\n");
      format_modifiers |= FM_y;
      break;
    case 'z':     /* alias of Mandatory Access Control level info */
      trace("-z shows aliased MAC info\n");
      return "Don't understand MAC on Linux.";
      break;
    case '-':
      return "Embedded '-' among SysV options makes no sense.";
      break;
    case '\0':
      return "Please report the \"SysV \\0 can't happen\" bug.";
      break;
    default:
      return "Unsupported SysV option.";
    } /* switch */
  } /* while */
  return NULL;
}
示例#4
0
文件: parser.c 项目: DrinkShot/procps
/***************** parse SysV options, including Unix98  *****************/
static const char *parse_sysv_option(void){
  const char *arg;
  const char *err;

  flagptr = ps_argv[thisarg];
  while(*++flagptr){
    // Find any excuse to ignore stupid Unix98 misfeatures.
    //
    // This list of options is ONLY for those defined by the
    // "IEEE Std 1003.1, 2004 Edition", "ISO/IEC 9945:2003",
    // or "Version 2 of the Single Unix Specification".
    //
    // It may be time to re-think the existence of this list.
    // In the meantime, please do not add to it. The list is
    // intended to ONLY contain flags defined by the POSIX and UNIX
    // standards published by The Open Group, IEEE, and ISO.
    if(!strchr("aAdefgGlnoptuU", *flagptr)) not_pure_unix = 1;  // dude, -Z ain't in POSIX

    switch(*flagptr){
    case 'A':
      trace("-A selects all processes\n");
      all_processes = 1;
      break;
    case 'C': /* end */
      trace("-C select by process name\n");  /* Why only HP/UX and us? */
      arg=get_opt_arg();
      if(!arg) return _("list of command names must follow -C");
      err=parse_list(arg, parse_cmd);
      if(err) return err;
      selection_list->typecode = SEL_COMM;
      return NULL; /* can't have any more options */
    case 'F':  /* DYNIX/ptx -f plus sz,rss,psr=ENG between c and stime */
      trace("-F does fuller listing\n");
      format_modifiers |= FM_F;
      format_flags |= FF_Uf;
      unix_f_option = 1; /* does this matter? */
      break;
    case 'G': /* end */
      trace("-G select by RGID (supports names)\n");
      arg=get_opt_arg();
      if(!arg) return _("list of real groups must follow -G");
      err=parse_list(arg, parse_gid);
      if(err) return err;
      selection_list->typecode = SEL_RGID;
      return NULL; /* can't have any more options */
    case 'H':     /* another nice HP/UX feature */
      trace("-H process hierarchy (like ASCII art forest option)\n");
      forest_type = 'u';
      break;
#if 0
    case 'J':  // specify list of job IDs in hex (IRIX) -- like HP "-R" maybe?
      trace("-J select by job ID\n");  // want a JID ("jid") for "-j" too
      arg=get_opt_arg();
      if(!arg) return _("list of jobs must follow -J");
      err=parse_list(arg, parse_jid);
      if(err) return err;
      selection_list->typecode = SEL_JID;
      return NULL; /* can't have any more options */
#endif
    case 'L':  /*  */
      /* In spite of the insane 2-level thread system, Sun appears to
       * have made this option Linux-compatible. If a process has N
       * threads, ps will produce N lines of output. (not N+1 lines)
       * Zombies are the only exception, with NLWP==0 and 1 output line.
       * SCO UnixWare uses -L too.
       */
      trace("-L print LWP (thread) info\n");
      thread_flags |= TF_U_L;
//      format_modifiers |= FM_L;
      break;
    case 'M':  // typically the SELinux context
      trace("-M print security label for Mandatory Access Control\n");
      format_modifiers |= FM_M;
      break;
    case 'N':
      trace("-N negates\n");
      negate_selection = 1;
      break;
    case 'O': /* end */
      trace("-O is preloaded -o\n");
      arg=get_opt_arg();
      if(!arg) return _("format or sort specification must follow -O");
      defer_sf_option(arg, SF_U_O);
      return NULL; /* can't have any more options */
    case 'P':     /* SunOS 5 "psr" or unknown HP/UX feature */
      trace("-P adds columns of PRM info (HP-UX), PSR (SunOS), or capabilities (IRIX)\n");
      format_modifiers |= FM_P;
      break;
#if 0
    case 'R':    // unknown HP/UX feature, like IRIX "-J" maybe?
      trace("-R select by PRM group\n");
      arg=get_opt_arg();
      if(!arg) return _("list of PRM groups must follow -R");
      err=parse_list(arg, parse_prm);
      if(err) return err;
      selection_list->typecode = SEL_PRM;
      return NULL; /* can't have any more options */
#endif
    case 'T':
      /* IRIX 6.5 docs suggest POSIX threads get shown individually.
       * This would make -T be like -L, -m, and m. (but an extra column)
       * Testing (w/ normal processes) shows 1 line/process, not 2.
       * Also, testing shows PID==SPID for all normal processes.
       */
      trace("-T adds strange SPID column (old sproc() threads?)\n");
      thread_flags |= TF_U_T;
//      format_modifiers |= FM_T;
      break;
    case 'U': /* end */
      trace("-U select by RUID (supports names)\n");
      arg=get_opt_arg();
      if(!arg) return _("list of real users must follow -U");
      err=parse_list(arg, parse_uid);
      if(err) return err;
      selection_list->typecode = SEL_RUID;
      return NULL; /* can't have any more options */
    case 'V': /* single */
      trace("-V prints version\n");
      exclusive("-V");
      display_version();
      exit(0);
    // This must be verified against SVR4-MP. (UnixWare or Powermax)
    // Leave it undocumented until that problem is solved.
    case 'Z':     /* full Mandatory Access Control level info */
      trace("-Z shows full MAC info\n");
      format_modifiers |= FM_M;
      break;
    case 'a':
      trace("-a select all with a tty, but omit session leaders\n");
      simple_select |= SS_U_a;
      break;
    case 'c':
      /* HP-UX and SunOS 5 scheduling info modifier */
      trace("-c changes scheduling info\n");
      format_modifiers |= FM_c;
      break;
    case 'd':
      trace("-d select all, but omit session leaders\n");
      simple_select |= SS_U_d;
      break;
    case 'e':
      trace("-e selects all processes\n");
      all_processes = 1;
      break;
    case 'f':
      trace("-f does full listing\n");
      format_flags |= FF_Uf;
      unix_f_option = 1; /* does this matter? */
      break;
    case 'g': /* end */
      trace("-g selects by session leader OR by group name\n");
      arg=get_opt_arg();
      if(!arg) return _("list of session leaders OR effective group names must follow -g");
      err=parse_list(arg, parse_pid);
      if(!err){
        selection_list->typecode = SEL_SESS;
        return NULL; /* can't have any more options */
      }
      err=parse_list(arg, parse_gid);
      if(!err){
        selection_list->typecode = SEL_EGID;
        return NULL; /* can't have any more options */
      }
      return _("list of session leaders OR effective group IDs was invalid");
    case 'j':
      trace("-j jobs format\n");
      /* old Debian used RD_j and Digital uses JFMT */
      if(sysv_j_format) format_flags |= FF_Uj;
      else format_modifiers |= FM_j;
      break;
    case 'l':
      trace("-l long format\n");
      format_flags |= FF_Ul;
      break;
    case 'm':
      trace("-m shows threads\n");
      /* note that AIX shows 2 lines for a normal process */
      thread_flags |= TF_U_m;
      break;
    case 'n': /* end */
      trace("-n sets namelist file\n");
      arg=get_opt_arg();
      if(!arg) return _("alternate System.map file must follow -n");
      namelist_file = arg;
      return NULL; /* can't have any more options */
    case 'o': /* end */
      /* Unix98 has gross behavior regarding this. From the following: */
      /*            ps -o pid,nice=NICE,tty=TERMINAL,comm              */
      /* The result must be 2 columns: "PID NICE,tty=TERMINAL,comm"    */
      /* Yes, the second column has the name "NICE,tty=TERMINAL,comm"  */
      /* This parser looks for any excuse to ignore that braindamage.  */
      trace("-o user-defined format\n");
      arg=get_opt_arg();
      if(!arg) return _("format specification must follow -o");
      not_pure_unix |= defer_sf_option(arg, SF_U_o);
      return NULL; /* can't have any more options */
    case 'p': /* end */
      trace("-p select by PID\n");
      arg=get_opt_arg();
      if(!arg) return _("list of process IDs must follow -p");
      err=parse_list(arg, parse_pid);
      if(err) return err;
      selection_list->typecode = SEL_PID;
      return NULL; /* can't have any more options */
#if 0
    case 'r':
      trace("-r some Digital Unix thing about warnings...\n");
      trace("   or SCO's option to chroot() for new /proc and /dev\n");
      return _("the -r option is reserved");
      break;
#endif
    case 's': /* end */
      trace("-s select processes belonging to the sessions given\n");
      arg=get_opt_arg();
      if(!arg) return _("list of session IDs must follow -s");
      err=parse_list(arg, parse_pid);
      if(err) return err;
      selection_list->typecode = SEL_SESS;
      return NULL; /* can't have any more options */
    case 't': /* end */
      trace("-t select by tty\n");
      arg=get_opt_arg();
      if(!arg) return _("list of terminals (pty, tty...) must follow -t");
      err=parse_list(arg, parse_tty);
      if(err) return err;
      selection_list->typecode = SEL_TTY;
      return NULL; /* can't have any more options */
    case 'u': /* end */
      trace("-u select by user effective ID (supports names)\n");
      arg=get_opt_arg();
      if(!arg) return _("list of users must follow -u");
      err=parse_list(arg, parse_uid);
      if(err) return err;
      selection_list->typecode = SEL_EUID;
      return NULL; /* can't have any more options */
    case 'w':
      trace("-w wide output\n");
      w_count++;
      break;
    case 'x':  /* behind personality until "ps -ax" habit is uncommon */
      if(personality & PER_SVR4_x){
        // Same as -y, but for System V Release 4 MP
        trace("-x works like Sun Solaris & SCO Unixware -y option\n");
        format_modifiers |= FM_y;
        break;
      }
      if(personality & PER_HPUX_x){
        trace("-x extends the command line\n");
        w_count += 2;
        unix_f_option = 1;
        break;
      }
      return _("must set personality to get -x option");
    case 'y':  /* Sun's -l hack (also: Irix "lnode" resource control info) */
      trace("-y print lnone info in UID/USER column or do Sun -l hack\n");
      format_modifiers |= FM_y;
      break;
#if 0
    // This must be verified against SVR4-MP (UnixWare or Powermax)
    case 'z':     /* alias of Mandatory Access Control level info */
      trace("-z shows aliased MAC info\n");
      format_modifiers |= FM_M;
      break;
    // Solaris 10 does this
    case 'z':     /* select by zone */
      trace("-z secects by zone\n");
      arg=get_opt_arg();
      if(!arg) return _("list of zones (contexts, labels, whatever?) must follow -z");
      err=parse_list(arg, parse_zone);
      if(err) return err;
      selection_list->typecode = SEL_ZONE;
      return NULL; /* can't have any more options */
#endif
    case '-':
      return _("embedded '-' among SysV options makes no sense");
      break;
    case '\0':
      catastrophic_failure(__FILE__, __LINE__, _("please report this bug"));
      break;
    default:
      return _("unsupported SysV option");
    } /* switch */
  } /* while */
  return NULL;
}