Ubuntuディスプレイ解像度をデフォルトで1920x1080にする

Ubuntuのディスプレイ解像度の変更を、OS起動時のデフォルト設定にする方法を記録します。

結論から言うと、"/etc/profile.d"ディレクトリ下に、拡張子".sh"を持つファイルをroot権限で作成し、

xrandr --newmode "1920x1080_60.00"  173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync
xrandr --addmode Virtual1 1920x1080_60.00

この2行のコマンドを書き込む。
そして、一回目だけ手動で1920x1080解像度を設定すれば、次から自動的に1920x1080に設定されるようになりました。

この初期化処理に必要な"/etc/profile.d"ディレクトリの役割から、詳しく解析していきます。



Introduction

Ubuntuをインストールした直後はデフォルトのディスプレイ解像度が小さく、使い勝手がよくありませんでした。
そこで前回は、ディスプレイ解像度を変更するやり方を記録しました1
しかし、これだけの操作ではシャットダウンによって変更がリセットされてしまいます。

そこで今回は、シャットダウンした後も同じディスプレイ解像度を持続させる方法を探りました。


Results

"profile"ファイルの解析

シャットダウン後もディスプレイ解像度を持続させるというのは、つまりOS起動時にディスプレイ解像度を自動的に変更させればよいでしょう。

OS起動時の自動化について少し調べると、どうやら"profile"というファイルがカギとなるみたいです。
早速whereisコマンドをつかって"profile"ファイルを探します。

$ whereis profile

profile: /etc/profile.d /etc/profile

どうやらprofileと名のつくファイルが2つ"/etc"ディレクトリにあるようです。
cdコマンドを使って"/etc"ディレクトリに行き、
catコマンドを使ってファイルの中身を見てみます。

$ cd /etc
/etc$ cat profile.d
cat: profile.d: Is a directory

"profile.d"はファイルではなくディレクトリですよと怒られてしまいました。
ここで".d"という拡張子はディレクトリを意味するのかと思って検索してみましたが、D言語のソースコードであるという解説が多く、いまいち要領を得ません。

ここではあまり気にせず、"profile.d"ディレクトリに入って"ls"コマンドでディレクトリの中身を見てみます。

/etc$ cd ./profile
/etc/profile.d$ ls
01-locale-fix.sh  bash_completion.sh     input-method-config.sh  xdg_dirs_desktop_session.sh
apps-bin-path.sh  cedilla-portuguese.sh  vte-2.91.sh

なにやら面白そうなファイルがたくさんいらっしゃいます。
まず目についたのは、どのファイルも".sh"の拡張子を持っていることです。
反射的にマニュアルを見てみました。

$ man sh

~
NAME
     dash — command interpreter (shell)
~

dashというコマンドのマニュアルが表示されてしまいました。
今調べている".sh"拡張子についての情報は得られないだろうと思ってこのマニュアルを流し読みしていると、予想外にもここで"profile"についての記述を見つけました。

~
     A login shell first reads commands from the files /etc/profile and .profile if they exist.
     If the environment variable ENV is set on entry to an interactive shell, or is set in the
     .profile of a login shell, the shell next reads commands from the file named in ENV. 
~

これによるとログイン後に、先程見つけた"/etc/profile"と、”.profile”というファイルが読み込まれ、コマンドが実行されるようです。

".profile"もすごく興味深いですが、ひとまず"/etc/profile"の解析に移ります。

$ cd /etc
/etc$ cat profile
# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).

if [ "${PS1-}" ]; then
  if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then
    # The file bash.bashrc already sets the default PS1.
    # PS1='\h:\w\$ '
    if [ -f /etc/bash.bashrc ]; then
      . /etc/bash.bashrc
    fi
  else
    if [ "`id -u`" -eq 0 ]; then
      PS1='# '
    else
      PS1='$ '
    fi
  fi
fi

if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi

すごそうな文字列が表示されました。
意味のわかりそうなところから読んでいきます。

# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
~

システムワイドな".profile"、とはどういう意味でしょうか。 ".profile"より広域に作用を及ぼせるのでしょうか。
よくわかりません。
先を読み進めます。

~
if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi

こいつは大変おもしろい記述です。
先程探索した"/etc/profile.d"について、
for i in /etc/profile.d/*.sh; do
つまりファイル名の最後に".sh"のつくファイルを順番に"do"する、という意味でしょう。
確かに、"/etc/profile.d"に入っているファイルはすべて".sh"がついていました。

だんだんと各profileファイルの機能が明らかになってきました。
一度、整理します。

"/etc/profile" :
 ログイン後に読まれる。
 "/etc/profile.d"に入っている".sh"のつくファイルを実行する。

"/etc/profile.d" :
 ".sh"のつくファイルが入っている。

".profile" :
 ログイン後に読まれる。


"/etc/profile.d"に新しい".sh"ファイルを置く

ここまでの結果から考えると、"/etc/profile.d"に新しく自分で書いた".sh"ファイルを置いておけば、そこに記述されたコマンドがログイン後に実行される、ということが期待できます。

ファイルを作るためには、"vim"というテキストエディタを使いました。
インストールされていない場合は、$ sudo apt install vimでインストールできます。
vimの使い方についてはそのうち備忘録を書く予定です。

さっそくvimをつかって、"/etc/profile.d"ディレクトリに".sh"ファイルを作成してみます。

$ cd /etc/profile.d
/etc/profile.d$ vim test.sh

しかし、ここで問題が発生しました。
"test.sh"というファイルをvimで作成し、"/etc/profile.d"ディレクトリの中に保存しようとしたのですが、エラーを吐かれてしましました。

"test.sh" E212: Can't open file for writing

これは由々しき問題です。 ファイルの書き込みはできない、と怒られてしまったわけです。
これでは"/etc/profile.d"ディレクトリの中に独自の".sh"ファイルを作成する、という戦術が成り立ちません。

ここでしばらく解決策を模索していると、面白い概念を発見しました。
"パーミッション"という考え方です。

Archwikiによると2

File systems use permissions and attributes to regulate the level of interaction that system processes can have with files and directories.

ファイルやディレクトリは、やり取りできるレベルが"パーミッション"によって制御されているそうです。
どのようにしてパーミッションを調べられるのかについてここで書くとあまりに長くなってしまうので、それは別の機会に詳述しようと思います3

ところで、先程書き込みができなかった"/etc/profile.d"ディレクトリですが、このパーミッションを調べてみると、書き込みが許可されているのは"root"のみとなっていました。

つまり、"root"の権限を持ってすれば、"/etc/profile.d"ディレクトリに書き込みができそうです。

sudoコマンドを用いて、root権限のもとでファイルを作成してみます。

/etc/profile.d$ sudo vim my_commands.sh

すると、見事この"my_commands.sh"というファイルを"/etc/profile.d"ディレクトリに作成することができました。


コマンドを".sh"ファイルに書き込む

あとは、"/etc/profile.d"ディレクトリに作成した".sh"ファイルに、自分が実行させたいコマンドを書き込めば、うまくいくはずです。

ディスプレイ解像度を変更するコマンドは、前回の記事4で判明しました。
先程"/etc/profile.d"ディレクトリに作成した"my_commands.sh"に、それらのコマンドを書き込んでいきます。

xrandr --newmode "1920x1080_60.00"  173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync
xrandr --addmode Virtual1 1920x1080_60.00
xrandr --output Virtual1 --mode 1920x1080_60.00

しかし、これで再起動しても、なぜか解像度は1920x1080にはなりません。私の場合、再起動直前に設定していた1680x1050になってしまいました。

いろいろと試行錯誤をして、わかったことがいくつかあります。

まず、ディスプレイ解像度が1920x1080になっていなくとも、設定の中に1920x1080は追加されているということ。
ここで、シャットダウン前に解像度を1920x1080に設定しておくと、再起動後も1920x1080になるということ。
そのためには、コマンド3行目xrandr --output Virtual1 --mode 1920x1080_60.00は必要ないということ。

つまり、一度手動で解像度1920x1080にしてしまえば、"my_commands.sh"に書き込むコマンドは、

xrandr --newmode "1920x1080_60.00"  173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync
xrandr --addmode Virtual1 1920x1080_60.00

この2行のみで、自動的に解像度が1920x1080に設定されるようになる、ということがわかりました。


Discussion

今回、OS起動後に自動的に解像度1920x1080が設定される方法を記録しました。

しかし、正直クールな解決方法とは言い難いです。
解像度の出力を変更するコマンド
xrandr --output Virtual1 --mode 1920x1080_60.00
が機能せず、一度手動で解像度を変更する必要があったからです。
なんで機能しなかったんでしょうか。 気が向いたときに追求することにします。

ところで、、"/etc/profile.d"に入っていたほかの.shファイルや、".profile"はどんな操作を実行しているのでしょうか。 書き換えても問題ないものなのでしょうか。
きっと問題があるからrootしか書き込みが許可されていないのでしょうね。 いじってみるのも面白そうです。

しかし、こうしてUbuntuをいじり倒しているうちに、段々とコマンドの使い方を覚えてきました。 忘れないためにも、そのうち記録を残したいと思っています。


See also

www.bioerrorlog.work

www.bioerrorlog.work