試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

Ubuntu Gutsy(7.10)でuswsusp関連の設定を半自動で行うスクリプトを試作

Ubuntu Gutsy(7.10)でuswsusp + hibernate-scriptによるハイバネーションを行う」で行った作業は結構面倒なので、その何倍もの手間をかけて、この作業を半自動化してみる実験。「Ubuntu Gutsy(7.10)でuswsuspのスワップ「ファイル」からの復帰ができなかった件の対処と、ファイルへの書き込みの流れ」をもとに、ファイルへの書き込みも、選択により、必要な作業を半自動で行う。

このスクリプトは、

  • uswsuspの設定を行う際のインターフェースが端末(Dialog)になっている場合にDebConfの再設定をさせる(「Gnome」を選択することで、以降の設定がGUIになる)
  • uswsuspとhibernateのいずれかがインストールされていない場合に自動でインストール
  • スワップファイルへ書き込む場合に、「ファイル作成/初期化/fstabへ登録/swapon/位置情報(resume offset)の自動設定」を行い、スワップファイルを含むパーティションを選択させての反映も行う
  • hibernate-scriptでuswsuspを優先して使用するための設定(自動)
  • パスワード無しでhibernate-scriptを実行するためのsudoの設定を自動で行うか、もしくは、geditテキストエディタを使用してvisudoを実行
  • 確認ダイアログの出るラッパースクリプトと、これを実行するランチャをインストール

といった作業を行うが、手動で設定ファイルを編集する部分が省略(自動化)できるのは大きい。
ファイル選択や、スワップファイルのサイズ指定、スワップファイルのあるパーティション選択などに、zenityを使用して、GUIでの入力を可能にしている。ダイアログ表示にも使用している。
一部、メッセージを「はい/いいえ」にしたかったが「OK/キャンセル」にしかならない部分もあるので、「キャンセル」を「いいえ」に読み替える必要のあるところもある。
また、何かしらの不具合が含まれている可能性もあるので注意。

[任意]ファイル名: uswsusp-config-gutsy.sh

#! /bin/bash

USWSUSP_CONF=/etc/uswsusp.conf
HIBERNATE_CONF=/etc/hibernate/hibernate.conf
WRAPPER=/usr/local/bin/hibernate-wrapper
LAUNCHER=/home/${SUDO_USER}/デスクトップ/休止状態.desktop

cancel() {
  zenity --info --title "取り消し" --text "キャンセルされたので、終了します。"
  exit 1
}

die() {
  zenity --error --title "エラー" --text "エラーが発生しました"
  exit 1
}

# 一般ユーザ権限で実行したらエラー
if [ $(whoami) != "root" ]; then
  zenity --error --title "管理者権限で実行してください" --text "\
このスクリプトは、ファイルマネージャの右クリックメニューの
「別のアプリで開く」から「コマンドを指定する」に
「gksudo」と入れて実行してください。
2回目以降は、メニューの「\"gksudo\" で開く」から実行できます。"
  exit 1
fi

# 実行中であることを示すためにシステムトレイを使用
exec 3> >(zenity --notification --window-icon /usr/share/pixmaps/ubuntu.svg --text "uswsusp設定ツールの動作中" --listen)

# DebConfが端末に設定されていたら変更させる
debconf-show debconf 2> /dev/null | grep "frontend: Dialog" >/dev/null
if [ $? = 0 ]; then
  echo "tooltip: DebConf設定ツールの設定" >&3
  zenity --info --title "DebConfの設定" --text "\
uswsuspの設定をGUIで行うのに必要な設定を
はじめに行っておくことを推奨します。
キーボードの矢印キーで「Gnome」を選んでEnterを押してください。
その後の質問には、そのままEnterを押していけばOKです。
(一度設定を行えば、2回目以降これを行う必要はありません)"
  gnome-terminal -t 'DebConf設定ツールの設定' --hide-menubar -x dpkg-reconfigure debconf
fi

# uswsuspとhibernateがインストールされているかをチェック
USWSUSP_HIBERNATE=$(dpkg-query -W -f='${Status}\n' uswsusp hibernate | grep "install ok installed" | wc -l)
if [ ${USWSUSP_HIBERNATE} != 2 ]; then
  echo "tooltip: uswsuspとhibernateをインストール" >&3
  zenity --info --title "パッケージの自動インストール" --text "\
uswsuspもしくはhibernateのパッケージががインストールされていません。
自動的にインストールされるので、
終了するまでの間、出てきた端末を閉じないでください。

「利用可能なスワップ領域がありませんが、続行しますか?」
とだけ表示されたら、キャンセルせず、「次へ」をクリックしてください。
設定は後で行われます。"
  # インストール
  gnome-terminal -t 'インストール中...' --hide-menubar -x apt-get -y install uswsusp hibernate
fi

# ファイルへのイメージ書き込みを行うか質問
echo "tooltip: イメージ書き込みの質問" >&3
zenity --question --title "ファイルへのイメージ書き込みを行いますか?" --text "\
ファイルへのメモリイメージ書き込みを行うことはできますが、
DebConf設定ツールでは
ファイルへの書き込みを設定することができないため、
本ツールで補助的な作業を行います。

ファイルへのイメージ書き込みを行いますか?"
if [ $? = 0 ]; then  # ファイルへ書き込む
  echo "tooltip: スワップファイルの質問" >&3
  zenity --question --title "スワップファイルを作成しますか?" --text "\
スワップファイルが作成されていない場合は、ここで作成してください。
作成しない場合は、
現在有効になっているスワップファイルの場所を指定してください。

注意:
一度作成したスワップファイルの場所を変更/削除した後には、
「gksudo gedit /etc/fstab」を実行して、
自動マウントの設定ファイル(/etc/fstab)を開いて、
スワップファイルの含まれる行を編集/削除する必要があります。

作成しますか?"
  if [ $? = 0 ]; then  # 新規作成
    SWFILE=$(zenity --file-selection --title "スワップファイルの保存先" --save --confirm-overwrite)
    if [ $? != 0 ]; then cancel; fi
    SWFSIZE=$(zenity --scale --title "スワップファイルのサイズ" --text "MiB単位でスワップフ ァイルのサイズを指定してください。" --min-value 32 --max-value 2048 --value 96 --step 16)
    if [ $? != 0 ]; then cancel; fi
    echo "tooltip: スワップファイルの初期化中" >&3
    dd if=/dev/zero of=${SWFILE} bs=1M count=${SWFSIZE} || die
    mkswap ${SWFILE} || die
    # 自動マウントの設定後、有効にする
    echo ${SWFILE} none swap sw 0 0 >> /etc/fstab || die
    swapon -a || die
  else  # 既存のスワップファイルを選択
    SWFILE=$(zenity --file-selection --title "スワップファイルの選択")
    if [ $? != 0 ]; then cancel; fi
    # スワップとして使用されているか確認
    swapon -s | grep file | cut -d " " -f 1 | grep ${SWFILE} > /dev/null
    if [ $? != 0 ]; then
      zenity --error --title "使用されているスワップファイルではありません" --text "\
このファイル(${SWFILE})は、
現在使用されているスワップのリストに含まれていません。

正しいファイルを選択したか確認するか、新しく作り直してください。"
      exit 1
    fi
  fi

  echo "tooltip: スワップファイルを含むパーティションの質問" >&3
  DFT=0
  CMD="zenity --list --title スワップファイルを含むパーティションを選択 --text スワップファイルを含むパーティションを下から選択してください。 --radiolist --column 選択 --column デバイス名"
  CMD=${CMD}$(cat /etc/mtab | grep ^/dev/ | cut -d " " -f 1 | while read x; do if [ ${DFT} = 0 ]; then DFT=1; printf " true ${x}"; else printf " false ${x}"; fi; done)
  RESUMEDEV=$(${CMD})  # リスト選択を起動
  if [ $? != 0 ]; then cancel; fi

  # resume deviceを選択された値に置き換える
  sed -i -e "s|\(resume device =\).*$|\1 ${RESUMEDEV}|" ${USWSUSP_CONF}
  # resume offsetがあれば一旦消す
  sed -i -e 's/resume offset.*$//' -e '/^$/d' ${USWSUSP_CONF}
  # resume offsetを取得して設定ファイルに追記
  swap-offset ${SWFILE} >> ${USWSUSP_CONF}

  echo "tooltip: uswsuspの設定" >&3
  zenity --info --title "uswsuspの設定" --text "\
これから、uswsuspの設定を行います。
「利用可能なスワップ領域がありませんが、続行しますか?」は
そのままで、それ以外の設定項目を編集します。
デバイスノードやログレベルは空のままでも大丈夫です。
スワップ領域の選択はいじらないでください。"
else  # パーティションへ書き込む
  SWP=$(swapon -s | grep partition)
  if [ $? != 0 ]; then
    zenity --error --title "有効なスワップパーティションが存在しません" --text "\
有効なスワップパーティションが存在しないため、作業は続行できません。
再び実行後、スワップファイルを使用する設定を行ってください。"
    exit 1
  fi
  SWPDEV=$(echo ${SWP} | cut -d " " -f 1 | head -n 1)
  # resume offsetがあれば消す
  sed -i -e 's/resume offset.*$//' -e '/^$/d' ${USWSUSP_CONF}
  # UUID表記があればデバイス名に修正
  grep "resume device = UUID" ${USWSUSP_CONF} >/dev/null && sed -i -e "s/UUID=.*$/${SWPDEV}" ${USWSUSP_CONF}
  echo "tooltip: uswsuspの設定" >&3
  zenity --info --title "uswsuspの設定" --text "\
これから、uswsuspの設定を行います。
「利用可能なスワップ領域がありませんが、続行しますか?」は
そのままで、それ以外の設定項目を編集します。
デバイスノードやログレベルは空のままでも大丈夫です。
スワップ領域は、適切なものが選択されているかを確認してください。
(スワップファイルからパーティションに変更する場合は注意)"
fi
dpkg-reconfigure uswsusp

# uswsuspを優先させるようにhibernate scriptを設定
sed -i -e 's/^\(TryMethod suspend2.conf\)$/TryMethod ususpend-disk.conf\n\1/' ${HIBERNATE_CONF}

# sudoの設定
if [ $(grep HIBERNATE /etc/sudoers | wc -l) != 2 ]; then  # 未設定とみなす
  echo "tooltip: sudoの設定" >&3
  zenity --question --title "sudoの設定を自動で行いますか?" --text "\
休止をパスワード無しで実行するために、sudoの設定が必要です。
/etc/sudoersファイルを直接更新するのは推奨されず、
visudoというコマンドで編集するのが一般的です。
しかし、自動編集では一瞬で終わる上に楽です。

直接このファイルを自動で編集しますか?"
  if [ $? = 0 ]; then
    sed -i -e 's|^\(# Cmnd alias specification\)$|\1\nCmnd_Alias HIBERNATE=/usr/sbin/hibernate|' /etc/sudoers
    echo "%admin ALL=NOPASSWD: HIBERNATE" >> /etc/sudoers
  else
    zenity --info --no-wrap --title "手動編集" --text "\
「Cmnd alias」のセクションに「Cmnd_Alias HIBERNATE=/usr/sbin/hibernate」
最終セクションに「%admin ALL = NOPASSWD: HIBERNATE」を、それぞれ追加してください。"
    EDITOR=/usr/bin/gedit visudo
  fi
fi

# ラッパーの作成
if [ ! -f ${WRAPPER} ]; then
  cat <<EOF > ${WRAPPER}
#! /bin/dash

HIBERNATE_OPT="--force"
VERSTYLE_OPEN="<span style='italic' weight='bold' foreground='darkred'>"
VERSTYLE_CLOSE="</span>"

if [ "$1" != "-f" ]; then
  zenity --question --title="休止状態の確認" --text "\
uswsusp:\t\t\${VERSTYLE_OPEN}\$(dpkg-query -W -f='\${Version}\n' uswsusp)\${VERSTYLE_CLOSE}
hibernate-script:\t\${VERSTYLE_OPEN}\$(dpkg-query -W -f='\${Version}\n' hibernate)\${VERSTYLE_CLOSE}

休止しますか?"
  if [ \$? = 1 ]; then
    exit 1
  fi
fi

sudo /usr/sbin/hibernate \${HIBERNATE_OPT}
numlockx off; numlockx on
EOF
  chmod 755 ${WRAPPER}
fi

# .desktopファイルの作成
if [ ! -f ${LAUNCHER} ]; then
  cat <<EOF > ${LAUNCHER}
[Desktop Entry]
Encoding=UTF-8
Version=1.0
Type=Application
Terminal=false
Name[ja_JP]=休止状態
Exec=/usr/local/bin/hibernate-wrapper
Comment[ja_JP]=メモリの内容をディスクに書き込んで電源を切ります。
Icon[ja_JP]=ubuntu
Name=休止状態
Comment=メモリの内容をディスクに書き込んで電源を切ります。
Icon=ubuntu
EOF
  chown ${SUDO_UID}:${SUDO_GID} ${LAUNCHER}
fi

# 完了
echo "tooltip: 完了" >&3
zenity --info --title "設定完了" --text "\
以上で設定は終了です。お疲れさまでした。
休止を行うには、アイコンから実行するか、
「/usr/local/bin/hibernate-wrapper」を実行してください。"

この内容をコピペして保存し、ファイルマネージャの右クリックメニューから「別のアプリで開く」を選び、「コマンドを指定する」に「gksudo」と入力するなどして、管理者権限で実行する。

関連記事: