psコマンドのオプション、その解析方法


アニメ『音楽少女』

音楽家を両親に持つハナコ。ダンスを一回見ただけで振り付け完璧に覚えられるし、歌も覚えてしまいます。すごい才能です。さらに、各メンバーの個性も初見で把握、メンバー衣装のコーディネートもこなす。さらにさらに、タクシーは渋滞だからと3km走る体力まで持っています。そうです。ハナコは100億人に一人のアイドルなんです! ハナコ、当然アイドルになるものと思っていたら、アイドル「音楽少女」を応援するためのスタッフになります。
へ? スタッフ?
まあ、いずれ本人もアイドルになるのでしょうけど、スタッフってのが面白かったので視聴始めました。

前回に引き続き、psコマンドのオプションの解析方法をソースから追っかけます。
前回、ps/parser.cに各オプション処理(case文)を見つけました。
ps/parser.cにはどのような関数があるでしょうか。

 228 static const char *parse_sysv_option(void){
 229   const char *arg;
 230   const char *err;
 231 
 232   flagptr = ps_argv[thisarg];
 233   while(*++flagptr){
 234     switch(*flagptr){
 235     case 'A':
 236       trace("-A selects all processes\n");
 237       all_processes = 1;
 238       break;

parse_sysv_optionという関数がありました。この関数の中でcase文がたくさん書かれておりオプション処理されています。関数名から分かる通り、SYSVオプションの処理のようです。つまり、SYSVオプションの処理以外は、別関数で処理していることでしょう。
この関数の使用箇所を探していきます。

同じくps/parser.cに、parse_sysv_option関数を呼び出している関数がありました。
parse_sysv_optionだけでなく、parse_gnu_optionや、parse_bsd_option関数も呼び出してますね。parse_all_optionsという関数名なので、おそらくここですべてのオプションを処理していると思います。

1102 /* First assume sysv, because that is the POSIX and Unix98 standard. */
1103 static const char *parse_all_options(void){
1104   const char *err = NULL;
1105   int at;
1106   while(++thisarg < ps_argc){
1107   trace("parse_all_options calling arg_type for \"%s\"\n", ps_argv[thisarg]
1108     at = arg_type(ps_argv[thisarg]);
1109     trace("ps_argv[thisarg] is %s\n", ps_argv[thisarg]);
1110     switch(at){
1111     case ARG_GNU:
1112       err = parse_gnu_option();
1113       break;
1114     case ARG_SYSV:
1115       if(!force_bsd){   /* else go past case ARG_BSD */
1116         err = parse_sysv_option();
1117         break;
1118     case ARG_BSD:
1119         if(force_bsd && !(personality & PER_FORCE_BSD)) return _("way bad")
1120       }
1121       prefer_bsd_defaults = 1;
1122       err = parse_bsd_option();
1123       break;

GNU、SYSV、BSDそれぞれの分岐は1108行目のarg_type関数で決められているようです。

では、arg_typeを見てみましょう。

1083 static int arg_type(const char *str){
1084   int tmp = str[0];
1085   if((tmp>='a') && (tmp<='z'))   return ARG_BSD;
1086   if((tmp>='A') && (tmp<='Z'))   return ARG_BSD;
1087   if((tmp>='0') && (tmp<='9'))   return ARG_PID;
1088   if(tmp=='+')                   return ARG_SESS;
1089   if(tmp!='-')                   return ARG_FAIL;
1090   tmp = str[1];
1091   if((tmp>='a') && (tmp<='z'))   return ARG_SYSV;
1092   if((tmp>='A') && (tmp<='Z'))   return ARG_SYSV;
1093   if((tmp>='0') && (tmp<='9'))   return ARG_PGRP;
1094   if(tmp!='-')                   return ARG_FAIL;
1095   tmp = str[2];
1096   if((tmp>='a') && (tmp<='z'))   return ARG_GNU;
1097   if((tmp>='A') && (tmp<='Z'))   return ARG_GNU;
1098   if(tmp=='\0')                  return ARG_END;
1099                                  return ARG_FAIL;
1100 }

なんと!
複雑なオプションは、やはり複雑な処理で解析されていたんですね。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA