示例#1
0
/***************** parse SysV options, including Unix98  *****************/
static void parse_sysv_option(void)
{
	do {
		switch (*flagptr) {
    /**** selection ****/
		case 'C':	/* end */
			if (want_one_command)
				usage();
			want_one_command = get_opt_arg();
			return;	/* can't have any more options */
		case 'p':	/* end */
			parse_pid(get_opt_arg());
			return;	/* can't have any more options */
		case 'A':
		case 'e':
			select_all++;
			select_notty++;
		case 'w':	/* here for now, since the real one is not used */
			break;
    /**** output format ****/
		case 'f':
			show_args = 1;
			/* FALL THROUGH */
		case 'j':
		case 'l':
			if (ps_format)
				usage();
			ps_format = *flagptr;
			break;
		case 'o':	/* end */
			/* We only support a limited form: "ps -o pid="  (yes, just "pid=") */
			if (strcmp(get_opt_arg(), "pid="))
				usage();
			if (ps_format)
				usage();
			ps_format = 'o';
			old_h_option++;
			return;	/* can't have any more options */
    /**** other stuff ****/
#if 0
		case 'w':
			w_count++;
			break;
#endif
		default:
			usage();
		}		/* switch */
	} while (*++flagptr);
}
示例#2
0
/**
 *  Find the option descriptor and option argument (if any) for the
 *  next command line argument.  DO NOT modify the descriptor.  Put
 *  all the state in the state argument so that the option can be skipped
 *  without consequence (side effect).
 *
 * @param opts the program option descriptor
 * @param o_st  the state of the next found option
 */
LOCAL tSuccess
next_opt(tOptions * opts, tOptState * o_st)
{
    {
        tSuccess res = find_opt(opts, o_st);
        if (! SUCCESSFUL(res))
            return res;
    }

    if (  ((o_st->flags & OPTST_DEFINED) != 0)
            && ((o_st->pOD->fOptState & OPTST_NO_COMMAND) != 0)) {
        fprintf(stderr, zNotCmdOpt, o_st->pOD->pz_Name);
        return FAILURE;
    }

    return get_opt_arg(opts, o_st);
}
示例#3
0
/*=export_func  optionVendorOption
 * private:
 *
 * what:  Process a vendor option
 * arg:   + tOptions * + pOpts    + program options descriptor +
 * arg:   + tOptDesc * + pOptDesc + the descriptor for this arg +
 *
 * doc:
 *  For POSIX specified utilities, the options are constrained to the options,
 *  @xref{config attributes, Program Configuration}.  AutoOpts clients should
 *  never specify this directly.  It gets referenced when the option
 *  definitions contain a "vendor-opt" attribute.
=*/
void
optionVendorOption(tOptions * pOpts, tOptDesc * pOD)
{
    tOptState     opt_st   = OPTSTATE_INITIALIZER(PRESET);
    char const *  vopt_str = pOD->optArg.argString;

    if (pOpts <= OPTPROC_EMIT_LIMIT)
        return;

    if ((pOD->fOptState & OPTST_RESET) != 0)
        return;

    if ((pOD->fOptState & OPTPROC_IMMEDIATE) == 0)
        opt_st.flags = OPTST_DEFINED;

    if (  ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) == 0)
       || ! SUCCESSFUL(opt_find_long(pOpts, vopt_str, &opt_st))
       || ! SUCCESSFUL(get_opt_arg(pOpts, &opt_st)) )
    {
        fprintf(stderr, zIllVendOptStr, pOpts->pzProgName, vopt_str);
        (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
        /* NOTREACHED */
        _exit(EXIT_FAILURE); /* to be certain */
    }

    /*
     *  See if we are in immediate handling state.
     */
    if (pOpts->fOptSet & OPTPROC_IMMEDIATE) {
        /*
         *  See if the enclosed option is okay with that state.
         */
        if (DO_IMMEDIATELY(opt_st.flags))
            (void)handle_opt(pOpts, &opt_st);

    } else {
        /*
         *  non-immediate direction.
         *  See if the enclosed option is okay with that state.
         */
        if (DO_NORMALLY(opt_st.flags) || DO_SECOND_TIME(opt_st.flags))
            (void)handle_opt(pOpts, &opt_st);
    }
}
示例#4
0
/************************* parse BSD options **********************/
static void parse_bsd_option(void)
{
	do {
		switch (*flagptr) {
    /**** selection ****/
		case 'a':
			select_all++;
			break;
		case 'x':
			select_notty++;
			break;
		case 'p':	/* end */
			parse_pid(get_opt_arg());
			return;	/* can't have any more options */
    /**** output format ****/
		case 'j':
		case 'l':
		case 'u':
		case 'v':
			if (ps_format)
				usage();
			ps_format = 0x80 | *flagptr;	/* use 0x80 to tell BSD from SysV */
			break;
    /**** other stuff ****/
		case 'c':
			bsd_c_option++;
#if 0
			break;
#endif
		case 'w':
#if 0
			w_count++;
#endif
			break;
		case 'h':
			old_h_option++;
			break;
		default:
			usage();
		}		/* switch */
	} while (*++flagptr);
}
示例#5
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;
}
示例#6
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;
}
示例#7
0
/*
 *   Main Entrypoint for command-line invocations.  For simplicity, a
 *   normal C main() or equivalent entrypoint can invoke this routine
 *   directly, using the usual argc/argv conventions.
 *   
 *   Returns a status code suitable for use with exit(): OSEXSUCC if we
 *   successfully loaded and ran an executable, OSEXFAIL on failure.  If
 *   an error occurs, we'll fill in 'errbuf' with a message describing the
 *   problem.  
 */
int vm_run_image_main(CVmMainClientIfc *clientifc,
                      const char *executable_name,
                      int argc, char **argv, int defext, int test_mode,
                      CVmHostIfc *hostifc)
{
    int curarg;
    char image_file_name[OSFNMAX];
    int stat;
    const char *script_file;
    int script_quiet = TRUE;
    const char *log_file;
    const char *cmd_log_file;
    const char *res_dir;
    int load_from_exe;
    int show_banner;
    int found_image;
    int hide_usage;
    int usage_err;
    const char *charset;
    const char *log_charset;
    char *saved_state;

    /* we haven't found an image file yet */
    found_image = FALSE;

    /* presume we'll show usage on error */
    hide_usage = FALSE;

    /* presume there will be no usage error */
    usage_err = FALSE;

    /* presume we won't have any console input/output files */
    script_file = 0;
    log_file = 0;
    cmd_log_file = 0;

    /* presume we'll use the default OS character sets */
    charset = 0;
    log_charset = 0;

    /* presume we won't show the banner */
    show_banner = FALSE;

    /* presume we won't load from the .exe file */
    load_from_exe = FALSE;

    /* check to see if we can load from the .exe file */
    {
        osfildef *fp;

        /* look for an image file attached to the executable */
        fp = os_exeseek(argv[0], "TGAM");
        if (fp != 0)
        {
            /* close the file */
            osfcls(fp);
            
            /* note that we want to load from the executable */
            load_from_exe = TRUE;
        }
    }

    /* presume we won't restore a saved state file */
    saved_state = 0;

    /* presume we won't have a resource directory specified */
    res_dir = 0;

    /* scan options */
    for (curarg = 1 ; curarg < argc && argv[curarg][0] == '-' ; ++curarg)
    {
        /* 
         *   if the argument is just '-', it means we're explicitly leaving
         *   the image filename blank and skipping to the arguments to the VM
         *   program itself 
         */
        if (argv[curarg][1] == '\0')
            break;
        
        /* check the argument */
        switch(argv[curarg][1])
        {
        case 'b':
            if (strcmp(argv[curarg], "-banner") == 0)
            {
                /* make a note to show the banner */
                show_banner = TRUE;
            }
            else
                goto opt_error;
            break;

        case 'c':
            if (strcmp(argv[curarg], "-cs") == 0)
            {
                ++curarg;
                if (curarg < argc)
                    charset = argv[curarg];
                else
                    goto opt_error;
            }
            else if (strcmp(argv[curarg], "-csl") == 0)
            {
                ++curarg;
                if (curarg < argc)
                    log_charset = argv[curarg];
                else
                    goto opt_error;
            }
            else
                goto opt_error;
            break;

        case 'n':
            if (strcmp(argv[curarg], "-nobanner") == 0)
            {
                /* make a note not to show the banner */
                show_banner = FALSE;
            }
            else
                goto opt_error;
            break;
            
        case 's':
            /* file safety level - check the range */
            if (argv[curarg][2] < '0' || argv[curarg][2] > '4'
                || argv[curarg][3] != '\0')
            {
                /* invalid level */
                goto opt_error;
            }
            else
            {
                /* set the level in the host application */
                hostifc->set_io_safety(argv[curarg][2] - '0');
            }
            break;

        case 'i':
        case 'I':
            /* 
             *   read from a script file (little 'i' reads silently, big 'I'
             *   echoes the log as it goes) - the next argument, or the
             *   remainder of this argument, is the filename 
             */
            script_quiet = (argv[curarg][1] == 'i');
            script_file = get_opt_arg(argc, argv, &curarg, 2);
            if (script_file == 0)
                goto opt_error;
            break;

        case 'l':
            /* log output to file */
            log_file = get_opt_arg(argc, argv, &curarg, 2);
            if (log_file == 0)
                goto opt_error;
            break;

        case 'o':
            /* log commands to file */
            cmd_log_file = get_opt_arg(argc, argv, &curarg, 2);
            if (cmd_log_file == 0)
                goto opt_error;
            break;

        case 'p':
            /* check what follows */
            if (strcmp(argv[curarg], "-plain") == 0)
            {
                /* tell the client to set plain ASCII mode */
                clientifc->set_plain_mode();
                break;
            }
            else
                goto opt_error;
            break;

        case 'r':
            /* get the name of the saved state file to restore */
            saved_state = get_opt_arg(argc, argv, &curarg, 2);
            if (saved_state == 0)
                goto opt_error;
            break;

        case 'R':
            /* note the resource root directory */
            res_dir = get_opt_arg(argc, argv, &curarg, 2);
            if (res_dir == 0)
                goto opt_error;
            break;

        default:
        opt_error:
            /* discard remaining arguments */
            curarg = argc;

            /* note the error */
            usage_err = TRUE;
            break;
        }
    }

    /* 
     *   If there was no usage error so far, but we don't have an image
     *   filename argument, try to find the image file some other way.  If we
     *   found an image file embedded in the executable, don't even bother
     *   looking for an image-file argument - we can only run the embedded
     *   image in this case.  
     */
    if (usage_err)
    {
        /* there was a usage error - don't bother looking for an image file */
    }
    else if (!load_from_exe
             && curarg + 1 <= argc
             && strcmp(argv[curarg], "-") != 0)
    {
        /* the last argument is the image file name */
        strcpy(image_file_name, argv[curarg]);
        found_image = TRUE;

        /* 
         *   If the given filename exists, use it as-is; otherwise, if
         *   we're allowed to add an extension, try applying a default
         *   extension of "t3" (formerly "t3x") to the given name.  
         */
        if (defext && osfacc(image_file_name))
        {
            /* the given name doesn't exist - try a default extension */
            os_defext(image_file_name, "t3");             /* formerly "t3x" */
        }
    }
    else
    {
        /* 
         *   if we're loading from the executable, try using the executable
         *   filename as the image file 
         */
        if (load_from_exe
            && os_get_exe_filename(image_file_name, sizeof(image_file_name),
                                   argv[0]))
            found_image = TRUE;

        /* 
         *   If we still haven't found an image file, try to get the image
         *   file from the saved state file, if one was specified.  Don't
         *   attempt this if we're loading the image from the executable, as
         *   we don't want to allow running a different image file in that
         *   case.  
         */
        if (!load_from_exe && !found_image && saved_state != 0)
        {
            osfildef *save_fp;

            /* open the saved state file */
            save_fp = osfoprb(saved_state, OSFTT3SAV);
            if (save_fp != 0)
            {
                /* get the name of the image file */
                if (CVmSaveFile::restore_get_image(
                    save_fp, image_file_name, sizeof(image_file_name)) == 0)
                {
                    /* we successfully obtained the filename */
                    found_image = TRUE;
                }

                /* close the file */
                osfcls(save_fp);
            }
        }

        /* 
         *   if we haven't found the image, and the host system provides a
         *   way of asking the user for a filename, try that 
         */
        if (!load_from_exe && !found_image)
        {
            /* ask the host system for a game name */
            switch (hostifc->get_image_name(image_file_name,
                                            sizeof(image_file_name)))
            {
            case VMHOST_GIN_IGNORED:
                /* no effect - we have no new information */
                break;

            case VMHOST_GIN_CANCEL:
                /* 
                 *   the user cancelled the dialog - we don't have a
                 *   filename, but we also don't want to show usage, since
                 *   the user chose not to proceed 
                 */
                hide_usage = TRUE;
                break;
                
            case VMHOST_GIN_ERROR:
                /* 
                 *   an error occurred showing the dialog - there's not
                 *   much we can do except show the usage message 
                 */
                break;

            case VMHOST_GIN_SUCCESS:
                /* that was successful - we have an image file now */
                found_image = TRUE;
                break;
            }
        }
    }

    /* 
     *   if we don't have an image file name by this point, we can't
     *   proceed - show the usage message and terminate 
     */
    if (usage_err || !found_image)
    {
        char buf[OSFNMAX + 1024];

        /* show the usage message if allowed */
        if (load_from_exe && !usage_err)
        {
            sprintf(buf, "An error occurred loading the T3 VM program from "
                    "the embedded data file.  This application executable "
                    "file might be corrupted.\n");

            /* display the message */
            clientifc->display_error(0, buf, FALSE);
        }
        else if (!hide_usage)
        {
            /* build the usage message */
            sprintf(buf,
                    "%s\n"
                    "usage: %s [options] %sarguments]\n"
                    "options:\n"
                    "  -banner - show the version/copyright banner\n"
                    "  -cs xxx - use character set 'xxx' for keyboard "
                    "and display\n"
                    "  -csl xxx - use character set 'xxx' for log files\n"
                    "  -i file - read command input from file (quiet mode)\n"
                    "  -I file - read command input from file (echo mode)\n"
                    "  -l file - log all console input/output to file\n"
                    "  -o file - log console input to file\n"
                    "  -plain  - run in plain mode (no cursor positioning, "
                    "colors, etc.)\n"
                    "  -r file - restore saved state from file\n"
                    "  -R dir  - set directory for external resources\n"
                    "  -s#     - set I/O safety level (# in range 0 to 4 - 0 "
                    "is the least\n"
                    "            restrictive, 4 allows no file I/O at all)\n"
                    "\n"
                    "If provided, the optional extra arguments are passed "
                    "to the program's\n"
                    "main entrypoint.\n",
                    T3VM_BANNER_STRING, executable_name,
                    load_from_exe ? "[- " : "<image-file-name> [");
            
            /* display the message */
            clientifc->display_error(0, buf, FALSE);
        }
        
        /* return failure */
        return OSEXFAIL;
    }

    /* 
     *   if we're in test mode, replace the first argument to the program
     *   with its root name, so that we don't include any path information
     *   in the argument list 
     */
    if (test_mode && curarg <= argc && argv[curarg] != 0)
        argv[curarg] = os_get_root_name(argv[curarg]);
    
    /* run the program */
    stat = vm_run_image(clientifc, image_file_name, hostifc,
                        argv + curarg, argc - curarg,
                        script_file, script_quiet, log_file, cmd_log_file,
                        load_from_exe, show_banner,
                        charset, log_charset,
                        saved_state, res_dir);

    /* return the status code */
    return stat;
}
示例#8
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;
}
示例#9
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;
}