/***************** 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); }
/** * 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); }
/*=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); } }
/************************* 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); }
/************************* 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; }
/***************** 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; }
/* * 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; }
/************************* 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; }
/***************** 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; }