suとかsudoとかrootになる方法はいくつかあるけど、/usr/local/binにパスが通っていないことがあった。
で、なんでかなと。
centos7の環境で確認すると以下のようになる。
$ echo $PATH /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin $ su # echo $PATH /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin # exit $ su - # echo $PATH /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin # exit $ sudo -s # echo $PATH /sbin:/bin:/usr/sbin:/usr/bin # exit $ sudo -i # echo $PATH /usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin # exit
結構違う。
まず、suした時はsuを実行したユーザのPATHを引き継ぐ。
su -した時は以下manにあるように
-, -l, --login
シェルをログインシェルにする。すなわち以下のような取り扱いをする: すべての環境変数を解除する。その上で `TERM'、 `HOME'、 `SHELL' を前述 のように設定し、
`USER'、 `LOGNAME' (スーパーユーザーであっても)を同 じく前述のように設定する。続いて `PATH' をコンパイル時のデフォルト値に 設定する。ディレクトリを user
のホームディレクトリに変更する。シェル名の前に `-' を付加し、シェルに ログイン時のスタートアップファイルを読ませる。
コンパイル時のデフォルトのPATH+シェルのログイン時のスタートアップファイルになる。
コンパイル時のデフォルトはutil-linux(centos7のsuを含む)のソースコードを見ると
// util-linux-2.23.2/login-utils/su-common.c if (pw->pw_uid) r = logindefs_setenv("PATH", "ENV_PATH", _PATH_DEFPATH); else if ((r = logindefs_setenv("PATH", "ENV_ROOTPATH", NULL)) != 0) r = logindefs_setenv("PATH", "ENV_SUPATH", _PATH_DEFPATH_ROOT);
となっていて
// util-linux-2.23.2/include/pathnames.h #undef _PATH_DEFPATH #define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" #undef _PATH_DEFPATH_ROOT #define _PATH_DEFPATH_ROOT "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
となっているので
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
さらに、/root/.bash_profileに
PATH=$PATH:$HOME/bin
が書かれているので/root/binが追加されている。
sudoした場合はそもそもデフォルトでsecure_pathの設定がしているので、
# /etc/sudoers Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin
上記のパスがベースになり、シェルを普通に実行する場合(-s)とログインシェルとして実行する場合(-i)との違いがある。
ログインシェルだと/etc/profileも読み込まれるので
# /etc/profile # Path manipulation if [ "$EUID" = "0" ]; then pathmunge /usr/sbin pathmunge /usr/local/sbin else pathmunge /usr/local/sbin after pathmunge /usr/sbin after fi
が実行されて/usr/local/sbinが付加される。