Unix/Linuxプログラミング理論と実践 第2章(プログラミング課題)
備忘録です.解答にはなっていないかったりします.
環境:FreeBSD 8.2-STABLE
http://www.amazon.co.jp/gp/product/4048700219
2.10 アイデンティティの危機
who am i
$ who am i
は
$ who -m
と同義.
manには「-m 標準入力に接続された端末情報のみを表示します。」と説明ある.
上記コマンドを実行すると,コマンドを実行した端末の情報のみを表示する.
who2.cを書き換える際の参考情報.
システムのstruct utmpの中から,標準入力に接続された端末の情報のみを表示する.
まずは,端末名を取得する.
ttyname()を使い,ファイルディスクリプを渡すと,ttyの名前を/dev/ttyxxの形式で返してくる.
なお,標準入力のファイルディスクリプタはSTDIN_FILENO.
#include <unistd.h> char* ttyname(int fd)
struct utmpのut_lineに端末名があるが,これはttyxxの形式で入っている.
それで,まずは/dev/ttyxxの形式からttyxxだけを抜き出す.
抜き出すために,次のライブラリ関数を利用できる.
strrchr()は,char型のポインタsが指す文字列中で,文字cが最後に出た場所のポインタを返す.
#include <string.h> char* strrchr(const char *s, int c);
whoami
$ whoami
は,
$ id -un
と同じ.
機能は,実効UID(Effective UID),つまりプログラム実行時の権限判断に利用するUIDの名前を表示することです.
$ who am i で表示されるのは,ユーザのログイン名.
whoamiコマンドはidコマンドと同じプログラムから生成(実行時にコマンド名で処理切り替え)するので,idコマンドのプログラムをチェックする.
id.cのl.174からが該当する処理です.
if (uflag) { id = pw ? pw->pw_uid : rflag ? getuid() : geteuid(); if (nflag && (pw = getpwuid(id))) (void)printf("%s\n", pw->pw_name); else (void)printf("%u\n", id); exit(0); }
まずは次の行.
id = pw ? pw->pw_uid : rflag ? getuid() : geteuid();
変数pwはl.79で定義されている.
struct passwd *pw;
passwd構造体は/usr/include/pwd.hのl.116から定義されている.
この構造体を,FreeBSDでユーザIDやパスワードの管理に利用している.$ man 5 passwd が参考になる.
struct passwd { char *pw_name; /* user name */ char *pw_passwd; /* encrypted password */ uid_t pw_uid; /* user uid */ gid_t pw_gid; /* user gid */ time_t pw_change; /* password change time */ char *pw_class; /* user access class */ char *pw_gecos; /* Honeywell login info */ char *pw_dir; /* home directory */ char *pw_shell; /* default shell */ time_t pw_expire; /* account expiration */ int pw_fields; /* internal: fields filled in */ };
変数pwは,id.cのl.153で初期化されている.
pw = *argv ? who(*argv) : NULL;
このときargvは,コマンド実行時のオプションの後ろを指している.
オプションの後ろには,ユーザ名 or ユーザIDを指定できることになっている.
つまり,ユーザ名orユーザIDを指定していればwho()が呼ばれ,何も指定していなければNULLがpwには入る.今はNULL.
戻って,次の行.pw==NULL,rflag==0なので,idにはgeteuid()の結果が返る.
geteuid()は呼び出しプロセスの実効ユーザIDを返す.
id = pw ? pw->pw_uid : rflag ? getuid() : geteuid();
次の行.nflag==1.getpwuid()はパスワードデータベースを検索して渡したidに該当する最初のエントリを返す.
struct passwdへのポインタがpwに返り,printf()でstruct passwdのpw_nameを表示する.
したがって,whoamiコマンドは,呼び出しプロセスの実効ユーザ名を表示する.
if (nflag && (pw = getpwuid(id))) (void)printf("%s\n", pw->pw_name);