471cf4cd36
Conflicts: pgrep.c proc/sysinfo.c ps/output.c skill.c top/top.c top/top.h w.c
1243 lines
39 KiB
C
1243 lines
39 KiB
C
/*
|
|
* parser.c - ps command options parser
|
|
* Copyright 1998-2003 by Albert Cahalan
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/* Ought to have debug print stuff like this:
|
|
* #define Print(fmt, args...) printf("Debug: " fmt, ## args)
|
|
*/
|
|
|
|
#include <grp.h>
|
|
#include <pwd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "../include/c.h"
|
|
#include "../include/xalloc.h"
|
|
|
|
#include "common.h"
|
|
|
|
#define ARG_GNU 0
|
|
#define ARG_END 1
|
|
#define ARG_PGRP 2
|
|
#define ARG_SYSV 3
|
|
#define ARG_PID 4
|
|
#define ARG_BSD 5
|
|
#define ARG_FAIL 6
|
|
#define ARG_SESS 7
|
|
|
|
static int w_count = 0;
|
|
|
|
static int ps_argc; /* global argc */
|
|
static char **ps_argv; /* global argv */
|
|
static int thisarg; /* index into ps_argv */
|
|
static char *flagptr; /* current location in ps_argv[thisarg] */
|
|
static int force_bsd = 0; /* set when normal parsing fails */
|
|
|
|
#define exclusive(x) if((ps_argc != 2) || strcmp(ps_argv[1],x)) \
|
|
return _("the option is exclusive: " x)
|
|
|
|
/********** utility functions **********/
|
|
static void display_ps_version(void)
|
|
{
|
|
fprintf(stdout, PROCPS_NG_VERSION);
|
|
}
|
|
|
|
|
|
/*
|
|
* Both "-Oppid" and "-O ppid" should be legal, though Unix98
|
|
* does not require it. BSD and Digital Unix allow both.
|
|
* Return the argument or NULL;
|
|
*/
|
|
static const char *get_opt_arg(void){
|
|
if(*(flagptr+1)){ /* argument is part of ps_argv[thisarg] */
|
|
return flagptr+1;
|
|
}
|
|
if(thisarg+2 > ps_argc) return NULL; /* there is nothing left */
|
|
/* argument follows ps_argv[thisarg] */
|
|
if(*(ps_argv[thisarg+1]) == '\0') return NULL;
|
|
return ps_argv[++thisarg];
|
|
}
|
|
|
|
/********** parse lists (of UID, tty, GID, PID...) **********/
|
|
|
|
static const char *parse_pid(char *str, sel_union *ret){
|
|
char *endp;
|
|
unsigned long num;
|
|
num = strtoul(str, &endp, 0);
|
|
if(*endp != '\0') return _("process ID list syntax error");
|
|
if(num<1) return _("process ID out of range");
|
|
if(num > 0x7fffffffUL) return _("process ID out of range");
|
|
ret->pid = num;
|
|
return 0;
|
|
}
|
|
|
|
static const char *parse_uid(char *str, sel_union *ret){
|
|
struct passwd *passwd_data;
|
|
char *endp;
|
|
unsigned long num;
|
|
num = strtoul(str, &endp, 0);
|
|
if(*endp != '\0'){ /* hmmm, try as login name */
|
|
passwd_data = getpwnam(str);
|
|
if(!passwd_data){
|
|
if(!negate_selection) return _("user name does not exist");
|
|
num = -1;
|
|
}
|
|
else
|
|
num = passwd_data->pw_uid;
|
|
}
|
|
if(!negate_selection && (num > 0xfffffffeUL)) return _("user ID out of range");
|
|
ret->uid = num;
|
|
return 0;
|
|
}
|
|
|
|
static const char *parse_gid(char *str, sel_union *ret){
|
|
struct group *group_data;
|
|
char *endp;
|
|
unsigned long num;
|
|
num = strtoul(str, &endp, 0);
|
|
if(*endp != '\0'){ /* hmmm, try as login name */
|
|
group_data = getgrnam(str);
|
|
if(!group_data){
|
|
if(!negate_selection) return _("group name does not exist");
|
|
num = -1;
|
|
}
|
|
else
|
|
num = group_data->gr_gid;
|
|
}
|
|
if(!negate_selection && (num > 0xfffffffeUL)) return _("group ID out of range");
|
|
ret->gid = num;
|
|
return 0;
|
|
}
|
|
|
|
static const char *parse_cmd(char *str, sel_union *ret){
|
|
strncpy(ret->cmd, str, sizeof ret->cmd); // strncpy pads to end
|
|
ret->cmd[sizeof(ret->cmd)-1] = '\0'; // but let's be safe
|
|
return 0;
|
|
}
|
|
|
|
static const char *parse_tty(char *str, sel_union *ret){
|
|
struct stat sbuf;
|
|
char path[4096];
|
|
if(str[0]=='/'){
|
|
if(stat(str, &sbuf) >= 0) goto found_it;
|
|
return _("TTY could not be found");;
|
|
}
|
|
#define lookup(p) \
|
|
snprintf(path,4096,p,str); \
|
|
if(stat(path, &sbuf) >= 0) goto found_it
|
|
|
|
lookup("/dev/pts/%s"); /* New Unix98 ptys go first */
|
|
lookup("/dev/%s");
|
|
lookup("/dev/tty%s");
|
|
lookup("/dev/pty%s");
|
|
lookup("/dev/%snsole"); /* "co" means "console", maybe do all VCs too? */
|
|
if(!strcmp(str,"-")){ /* "-" means no tty (from AIX) */
|
|
ret->tty = 0; /* processes w/o tty */
|
|
return 0;
|
|
}
|
|
if(!strcmp(str,"?")){ /* "?" means no tty, which bash eats (Reno BSD?) */
|
|
ret->tty = 0; /* processes w/o tty */
|
|
return 0;
|
|
}
|
|
if(!*(str+1) && (stat(str,&sbuf)>=0)){ /* Kludge! Assume bash ate '?'. */
|
|
ret->tty = 0; /* processes w/o tty */
|
|
return 0;
|
|
}
|
|
#undef lookup
|
|
return _("TTY could not be found");;
|
|
found_it:
|
|
if(!S_ISCHR(sbuf.st_mode)) return _("list member was not a TTY");
|
|
ret->tty = sbuf.st_rdev;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Used to parse lists in a generic way. (function pointers)
|
|
*/
|
|
static const char *parse_list(const char *arg, const char *(*parse_fn)(char *, sel_union *) ){
|
|
selection_node *node;
|
|
char *buf; /* temp copy of arg to hack on */
|
|
char *sep_loc; /* separator location: " \t," */
|
|
char *walk;
|
|
int items;
|
|
int need_item;
|
|
const char *err; /* error code that could or did happen */
|
|
/*** prepare to operate ***/
|
|
node = xmalloc(sizeof(selection_node));
|
|
node->u = xmalloc(strlen(arg)*sizeof(sel_union)); /* waste is insignificant */
|
|
node->n = 0;
|
|
buf = strdup(arg);
|
|
/*** sanity check and count items ***/
|
|
need_item = 1; /* true */
|
|
items = 0;
|
|
walk = buf;
|
|
err = _("improper list");
|
|
do{
|
|
switch(*walk){
|
|
case ' ': case ',': case '\t': case '\0':
|
|
if(need_item) goto parse_error;
|
|
need_item=1;
|
|
break;
|
|
default:
|
|
if(need_item) items++;
|
|
need_item=0;
|
|
}
|
|
} while (*++walk);
|
|
if(need_item) goto parse_error;
|
|
node->n = items;
|
|
/*** actually parse the list ***/
|
|
walk = buf;
|
|
while(items--){
|
|
sep_loc = strpbrk(walk," ,\t");
|
|
if(sep_loc) *sep_loc = '\0';
|
|
if(( err=(parse_fn)(walk, node->u+items) )) goto parse_error;
|
|
walk = sep_loc + 1; /* point to next item, if any */
|
|
}
|
|
free(buf);
|
|
node->next = selection_list;
|
|
selection_list = node;
|
|
return NULL;
|
|
parse_error:
|
|
free(buf);
|
|
free(node->u);
|
|
free(node);
|
|
return err;
|
|
}
|
|
|
|
/***************** parse SysV options, including Unix98 *****************/
|
|
static const char *parse_sysv_option(void){
|
|
const char *arg;
|
|
const char *err;
|
|
|
|
flagptr = ps_argv[thisarg];
|
|
while(*++flagptr){
|
|
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_ps_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 '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");
|
|
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 */
|
|
case 'q': /* end */
|
|
trace("-q quick select by PID.\n");
|
|
arg=get_opt_arg();
|
|
if(!arg) return "List of process IDs must follow -q.";
|
|
err=parse_list(arg, parse_pid);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_PID_QUICK;
|
|
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;
|
|
}
|
|
|
|
/************************* 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 '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 = xmalloc(sizeof(selection_node));
|
|
node->u = xmalloc(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_ps_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 'q': /* end */
|
|
trace("q Quick select by process ID\n");
|
|
arg=get_opt_arg();
|
|
if(!arg) return "List of process IDs must follow q.";
|
|
err=parse_list(arg, parse_pid);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_PID_QUICK;
|
|
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 = xmalloc(sizeof(selection_node));
|
|
node->u = xmalloc(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;
|
|
}
|
|
|
|
/*************** gnu long options **********************/
|
|
|
|
/*
|
|
* Return the argument or NULL
|
|
*/
|
|
static const char *grab_gnu_arg(void){
|
|
switch(*flagptr){ /* argument is part of ps_argv[thisarg] */
|
|
default:
|
|
return NULL; /* something bad */
|
|
case '=': case ':':
|
|
if(*++flagptr) return flagptr; /* found it */
|
|
return NULL; /* empty '=' or ':' */
|
|
case '\0': /* try next argv[] */
|
|
;
|
|
}
|
|
if(thisarg+2 > ps_argc) return NULL; /* there is nothing left */
|
|
/* argument follows ps_argv[thisarg] */
|
|
if(*(ps_argv[thisarg+1]) == '\0') return NULL;
|
|
return ps_argv[++thisarg];
|
|
}
|
|
|
|
typedef struct gnu_table_struct {
|
|
const char *name; /* long option name */
|
|
const void *jump; /* See gcc extension info. :-) */
|
|
} gnu_table_struct;
|
|
|
|
static int compare_gnu_table_structs(const void *a, const void *b){
|
|
return strcmp(((const gnu_table_struct*)a)->name,((const gnu_table_struct*)b)->name);
|
|
}
|
|
|
|
/* Option arguments are after ':', after '=', or in argv[n+1] */
|
|
static const char *parse_gnu_option(void){
|
|
const char *arg;
|
|
const char *err;
|
|
char *s;
|
|
size_t sl;
|
|
char buf[16];
|
|
gnu_table_struct findme = { buf, NULL};
|
|
gnu_table_struct *found;
|
|
static const gnu_table_struct gnu_table[] = {
|
|
{"Group", &&case_Group}, /* rgid */
|
|
{"User", &&case_User}, /* ruid */
|
|
{"cols", &&case_cols},
|
|
{"columns", &&case_columns},
|
|
{"context", &&case_context},
|
|
{"cumulative", &&case_cumulative},
|
|
{"deselect", &&case_deselect}, /* -N */
|
|
{"forest", &&case_forest}, /* f -H */
|
|
{"format", &&case_format},
|
|
{"group", &&case_group}, /* egid */
|
|
{"header", &&case_header},
|
|
{"headers", &&case_headers},
|
|
{"heading", &&case_heading},
|
|
{"headings", &&case_headings},
|
|
//{"help", &&case_help}, /* now TRANSLATABLE ! */
|
|
{"info", &&case_info},
|
|
{"lines", &&case_lines},
|
|
{"no-header", &&case_no_header},
|
|
{"no-headers", &&case_no_headers},
|
|
{"no-heading", &&case_no_heading},
|
|
{"no-headings", &&case_no_headings},
|
|
{"noheader", &&case_noheader},
|
|
{"noheaders", &&case_noheaders},
|
|
{"noheading", &&case_noheading},
|
|
{"noheadings", &&case_noheadings},
|
|
{"pid", &&case_pid},
|
|
{"ppid", &&case_ppid},
|
|
{"quick-pid", &&case_pid_quick},
|
|
{"rows", &&case_rows},
|
|
{"sid", &&case_sid},
|
|
{"sort", &&case_sort},
|
|
{"tty", &&case_tty},
|
|
{"user", &&case_user}, /* euid */
|
|
{"version", &&case_version},
|
|
{"width", &&case_width},
|
|
};
|
|
const int gnu_table_count = sizeof(gnu_table)/sizeof(gnu_table_struct);
|
|
|
|
s = ps_argv[thisarg]+2;
|
|
sl = strcspn(s,":=");
|
|
if(sl > 15) return _("unknown gnu long option");
|
|
strncpy(buf, s, sl);
|
|
buf[sl] = '\0';
|
|
flagptr = s+sl;
|
|
|
|
found = bsearch(&findme, gnu_table, gnu_table_count,
|
|
sizeof(gnu_table_struct), compare_gnu_table_structs
|
|
);
|
|
|
|
if(!found) {
|
|
if (!strcmp(buf, the_word_help))
|
|
goto case_help;
|
|
return _("unknown gnu long option");
|
|
}
|
|
|
|
goto *(found->jump); /* See gcc extension info. :-) */
|
|
|
|
case_Group:
|
|
trace("--Group\n");
|
|
arg = grab_gnu_arg();
|
|
if(!arg) return _("list of real groups must follow --Group");
|
|
err=parse_list(arg, parse_gid);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_RGID;
|
|
return NULL;
|
|
case_User:
|
|
trace("--User\n");
|
|
arg = grab_gnu_arg();
|
|
if(!arg) return _("list of real users must follow --User");
|
|
err=parse_list(arg, parse_uid);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_RUID;
|
|
return NULL;
|
|
case_cols:
|
|
case_width:
|
|
case_columns:
|
|
trace("--cols\n");
|
|
arg = grab_gnu_arg();
|
|
if(arg && *arg){
|
|
long t;
|
|
char *endptr;
|
|
t = strtol(arg, &endptr, 0);
|
|
if(!*endptr && (t>0) && (t<2000000000)){
|
|
screen_cols = (int)t;
|
|
return NULL;
|
|
}
|
|
}
|
|
return _("number of columns must follow --cols, --width, or --columns");
|
|
case_cumulative:
|
|
trace("--cumulative\n");
|
|
if(s[sl]) return _("option --cumulative does not take an argument");
|
|
include_dead_children = 1;
|
|
return NULL;
|
|
case_deselect:
|
|
trace("--deselect\n");
|
|
if(s[sl]) return _("option --deselect does not take an argument");
|
|
negate_selection = 1;
|
|
return NULL;
|
|
case_no_header:
|
|
case_no_headers:
|
|
case_no_heading:
|
|
case_no_headings:
|
|
case_noheader:
|
|
case_noheaders:
|
|
case_noheading:
|
|
case_noheadings:
|
|
trace("--noheaders\n");
|
|
if(s[sl]) return _("option --no-heading does not take an argument");
|
|
if(header_type) return _("only one heading option may be specified");
|
|
header_type = HEAD_NONE;
|
|
return NULL;
|
|
case_header:
|
|
case_headers:
|
|
case_heading:
|
|
case_headings:
|
|
trace("--headers\n");
|
|
if(s[sl]) return _("option --heading does not take an argument");
|
|
if(header_type) return _("only one heading option may be specified");
|
|
header_type = HEAD_MULTI;
|
|
return NULL;
|
|
case_forest:
|
|
trace("--forest\n");
|
|
if(s[sl]) return _("option --forest does not take an argument");
|
|
forest_type = 'g';
|
|
return NULL;
|
|
case_format:
|
|
trace("--format\n");
|
|
arg=grab_gnu_arg();
|
|
if(!arg) return _("format specification must follow --format");
|
|
defer_sf_option(arg, SF_G_format);
|
|
return NULL;
|
|
case_group:
|
|
trace("--group\n");
|
|
arg = grab_gnu_arg();
|
|
if(!arg) return _("list of effective groups must follow --group");
|
|
err=parse_list(arg, parse_gid);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_EGID;
|
|
return NULL;
|
|
case_help:
|
|
trace("--help\n");
|
|
arg = grab_gnu_arg();
|
|
do_help(arg, EXIT_SUCCESS);
|
|
case_info:
|
|
trace("--info\n");
|
|
exclusive("--info");
|
|
self_info();
|
|
exit(0);
|
|
return NULL;
|
|
case_pid:
|
|
trace("--pid\n");
|
|
arg = grab_gnu_arg();
|
|
if(!arg) return _("list of process IDs must follow --pid");
|
|
err=parse_list(arg, parse_pid);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_PID;
|
|
return NULL;
|
|
case_pid_quick:
|
|
trace("--quick-pid\n");
|
|
arg = grab_gnu_arg();
|
|
if(!arg) return "List of process IDs must follow --quick-pid.";
|
|
err=parse_list(arg, parse_pid);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_PID_QUICK;
|
|
return NULL;
|
|
case_ppid:
|
|
trace("--ppid\n");
|
|
arg = grab_gnu_arg();
|
|
if(!arg) return _("list of process IDs must follow --ppid");
|
|
err=parse_list(arg, parse_pid);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_PPID;
|
|
return NULL;
|
|
case_rows:
|
|
case_lines:
|
|
trace("--rows\n");
|
|
arg = grab_gnu_arg();
|
|
if(arg && *arg){
|
|
long t;
|
|
char *endptr;
|
|
t = strtol(arg, &endptr, 0);
|
|
if(!*endptr && (t>0) && (t<2000000000)){
|
|
screen_rows = (int)t;
|
|
return NULL;
|
|
}
|
|
}
|
|
return _("number of rows must follow --rows or --lines");
|
|
case_sid:
|
|
trace("--sid\n");
|
|
arg = grab_gnu_arg();
|
|
if(!arg) return _("some sid thing(s) must follow --sid");
|
|
err=parse_list(arg, parse_pid);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_SESS;
|
|
return NULL;
|
|
case_sort:
|
|
trace("--sort\n");
|
|
arg=grab_gnu_arg();
|
|
if(!arg) return _("long sort specification must follow --sort");
|
|
defer_sf_option(arg, SF_G_sort);
|
|
return NULL;
|
|
case_tty:
|
|
trace("--tty\n");
|
|
arg = grab_gnu_arg();
|
|
if(!arg) return _("list of ttys must follow --tty");
|
|
err=parse_list(arg, parse_tty);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_TTY;
|
|
return NULL;
|
|
case_user:
|
|
trace("--user\n");
|
|
arg = grab_gnu_arg();
|
|
if(!arg) return _("list of effective users must follow --user");
|
|
err=parse_list(arg, parse_uid);
|
|
if(err) return err;
|
|
selection_list->typecode = SEL_EUID;
|
|
return NULL;
|
|
case_version:
|
|
trace("--version\n");
|
|
exclusive("--version");
|
|
display_ps_version();
|
|
exit(0);
|
|
return NULL;
|
|
case_context:
|
|
trace("--context\n");
|
|
format_flags |= FF_Fc;
|
|
return NULL;
|
|
}
|
|
|
|
/*************** process trailing PIDs **********************/
|
|
static const char *parse_trailing_pids(void){
|
|
selection_node *pidnode; /* pid */
|
|
selection_node *grpnode; /* process group */
|
|
selection_node *sidnode; /* session */
|
|
char **argp; /* pointer to pointer to text of PID */
|
|
const char *err; /* error code that could or did happen */
|
|
int i;
|
|
|
|
i = ps_argc - thisarg; /* how many trailing PIDs, SIDs, PGRPs?? */
|
|
argp = ps_argv + thisarg;
|
|
thisarg = ps_argc - 1; /* we must be at the end now */
|
|
|
|
pidnode = xmalloc(sizeof(selection_node));
|
|
pidnode->u = xmalloc(i*sizeof(sel_union)); /* waste is insignificant */
|
|
pidnode->n = 0;
|
|
|
|
grpnode = xmalloc(sizeof(selection_node));
|
|
grpnode->u = xmalloc(i*sizeof(sel_union)); /* waste is insignificant */
|
|
grpnode->n = 0;
|
|
|
|
sidnode = xmalloc(sizeof(selection_node));
|
|
sidnode->u = xmalloc(i*sizeof(sel_union)); /* waste is insignificant */
|
|
sidnode->n = 0;
|
|
|
|
while(i--){
|
|
char *data;
|
|
data = *(argp++);
|
|
switch(*data){
|
|
default: err = parse_pid( data, pidnode->u + pidnode->n++); break;
|
|
case '-': err = parse_pid(++data, grpnode->u + grpnode->n++); break;
|
|
case '+': err = parse_pid(++data, sidnode->u + sidnode->n++); break;
|
|
}
|
|
if(err) return err; /* the node gets freed with the list */
|
|
}
|
|
|
|
if(pidnode->n){
|
|
pidnode->next = selection_list;
|
|
selection_list = pidnode;
|
|
selection_list->typecode = SEL_PID;
|
|
} /* else free both parts */
|
|
|
|
if(grpnode->n){
|
|
grpnode->next = selection_list;
|
|
selection_list = grpnode;
|
|
selection_list->typecode = SEL_PGRP;
|
|
} /* else free both parts */
|
|
|
|
if(sidnode->n){
|
|
sidnode->next = selection_list;
|
|
selection_list = sidnode;
|
|
selection_list->typecode = SEL_SESS;
|
|
} /* else free both parts */
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/************** misc stuff ***********/
|
|
|
|
static void reset_parser(void){
|
|
w_count = 0;
|
|
}
|
|
|
|
static int arg_type(const char *str){
|
|
int tmp = str[0];
|
|
if((tmp>='a') && (tmp<='z')) return ARG_BSD;
|
|
if((tmp>='A') && (tmp<='Z')) return ARG_BSD;
|
|
if((tmp>='0') && (tmp<='9')) return ARG_PID;
|
|
if(tmp=='+') return ARG_SESS;
|
|
if(tmp!='-') return ARG_FAIL;
|
|
tmp = str[1];
|
|
if((tmp>='a') && (tmp<='z')) return ARG_SYSV;
|
|
if((tmp>='A') && (tmp<='Z')) return ARG_SYSV;
|
|
if((tmp>='0') && (tmp<='9')) return ARG_PGRP;
|
|
if(tmp!='-') return ARG_FAIL;
|
|
tmp = str[2];
|
|
if((tmp>='a') && (tmp<='z')) return ARG_GNU;
|
|
if((tmp>='A') && (tmp<='Z')) return ARG_GNU;
|
|
if(tmp=='\0') return ARG_END;
|
|
return ARG_FAIL;
|
|
}
|
|
|
|
/* First assume sysv, because that is the POSIX and Unix98 standard. */
|
|
static const char *parse_all_options(void){
|
|
const char *err = NULL;
|
|
int at;
|
|
while(++thisarg < ps_argc){
|
|
trace("parse_all_options calling arg_type for \"%s\"\n", ps_argv[thisarg]);
|
|
at = arg_type(ps_argv[thisarg]);
|
|
trace("ps_argv[thisarg] is %s\n", ps_argv[thisarg]);
|
|
switch(at){
|
|
case ARG_GNU:
|
|
err = parse_gnu_option();
|
|
break;
|
|
case ARG_SYSV:
|
|
if(!force_bsd){ /* else go past case ARG_BSD */
|
|
err = parse_sysv_option();
|
|
break;
|
|
case ARG_BSD:
|
|
if(force_bsd && !(personality & PER_FORCE_BSD)) return _("way bad");
|
|
}
|
|
prefer_bsd_defaults = 1;
|
|
err = parse_bsd_option();
|
|
break;
|
|
case ARG_PGRP:
|
|
case ARG_SESS:
|
|
case ARG_PID:
|
|
prefer_bsd_defaults = 1;
|
|
err = parse_trailing_pids();
|
|
break;
|
|
case ARG_END:
|
|
case ARG_FAIL:
|
|
trace(" FAIL/END on [%s]\n",ps_argv[thisarg]);
|
|
return _("garbage option");
|
|
break;
|
|
default:
|
|
printf(" ? %s\n",ps_argv[thisarg]);
|
|
return _("something broke");
|
|
} /* switch */
|
|
if(err) return err;
|
|
} /* while */
|
|
return NULL;
|
|
}
|
|
|
|
static void choose_dimensions(void){
|
|
if(w_count && (screen_cols<132)) screen_cols=132;
|
|
if(w_count>1) screen_cols=OUTBUF_SIZE;
|
|
/* perhaps --html and --null should set unlimited width */
|
|
}
|
|
|
|
static const char *thread_option_check(void){
|
|
if(!thread_flags){
|
|
thread_flags = TF_show_proc;
|
|
return NULL;
|
|
}
|
|
|
|
if(forest_type){
|
|
return _("thread display conflicts with forest display");
|
|
}
|
|
//thread_flags |= TF_no_forest;
|
|
|
|
if((thread_flags&TF_B_H) && (thread_flags&(TF_B_m|TF_U_m)))
|
|
return _("thread flags conflict; can't use H with m or -m");
|
|
if((thread_flags&TF_B_m) && (thread_flags&TF_U_m))
|
|
return _("thread flags conflict; can't use both m and -m");
|
|
if((thread_flags&TF_U_L) && (thread_flags&TF_U_T))
|
|
return _("thread flags conflict; can't use both -L and -T");
|
|
|
|
if(thread_flags&TF_B_H) thread_flags |= (TF_show_proc|TF_loose_tasks);
|
|
if(thread_flags&(TF_B_m|TF_U_m)) thread_flags |= (TF_show_proc|TF_show_task|TF_show_both);
|
|
|
|
if(thread_flags&(TF_U_T|TF_U_L)){
|
|
if(thread_flags&(TF_B_m|TF_U_m|TF_B_H)){
|
|
// Got a thread style, so format modification is a requirement?
|
|
// Maybe -T/-L has H thread style though. (sorting interaction?)
|
|
//return _("Huh? Tell procps@freelists.org what you expected.");
|
|
thread_flags |= TF_must_use;
|
|
}else{
|
|
// using -L/-T thread style, so format from elsewhere is OK
|
|
thread_flags |= TF_show_task; // or like the H option?
|
|
//thread_flags |= TF_no_sort;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int arg_parse(int argc, char *argv[]){
|
|
const char *err = NULL;
|
|
const char *err2 = NULL;
|
|
ps_argc = argc;
|
|
ps_argv = argv;
|
|
thisarg = 0;
|
|
|
|
if(personality & PER_FORCE_BSD) goto try_bsd;
|
|
|
|
err = parse_all_options();
|
|
if(err) goto try_bsd;
|
|
err = thread_option_check();
|
|
if(err) goto try_bsd;
|
|
err = process_sf_options();
|
|
if(err) goto try_bsd;
|
|
err = select_bits_setup();
|
|
if(err) goto try_bsd;
|
|
|
|
choose_dimensions();
|
|
return 0;
|
|
|
|
try_bsd:
|
|
trace("--------- now try BSD ------\n");
|
|
|
|
reset_global();
|
|
reset_parser();
|
|
reset_sortformat();
|
|
format_flags = 0;
|
|
ps_argc = argc;
|
|
ps_argv = argv;
|
|
thisarg = 0;
|
|
/* no need to reset flagptr */
|
|
force_bsd=1;
|
|
prefer_bsd_defaults=1;
|
|
if(!( (PER_OLD_m|PER_BSD_m) & personality )) /* if default m setting... */
|
|
personality |= PER_OLD_m; /* Prefer old Linux over true BSD. */
|
|
/* Do not set PER_FORCE_BSD! It is tested below. */
|
|
|
|
err2 = parse_all_options();
|
|
if(err2) goto total_failure;
|
|
err2 = thread_option_check();
|
|
if(err2) goto total_failure;
|
|
err2 = process_sf_options();
|
|
if(err2) goto total_failure;
|
|
err2 = select_bits_setup();
|
|
if(err2) goto total_failure;
|
|
|
|
choose_dimensions();
|
|
return 0;
|
|
|
|
total_failure:
|
|
reset_parser();
|
|
if(personality & PER_FORCE_BSD) fprintf(stderr, _("error: %s\n"), err2);
|
|
else fprintf(stderr, _("error: %s\n"), err);
|
|
do_help(NULL, EXIT_FAILURE);
|
|
}
|