Termuxで家のPCの電源を一括で落とす

スマホから家のPCすべての電源を落とせるようにしたいと思い、色々調べた。最終的には、sshを使って各PCでshutdownコマンドを実行する方法に落ち着いた。

Termuxアプリのインストール

スマホからsshコマンドを実行するために、以下の記事を参考に作業しました。
https://qiita.com/Maki-HamarukiLab/items/05ccabba68703a7d7892

GitHubの公式情報によれば、Playストア版は実験ブランチらしいので、GitHubからリリース版(v0.118.1)をダウンロードしました。ちなみに、自分のスマホがARMv8だったのかも知らなかったので、そこから調べました。*1

Termuxの初期セットアップ

基本的に参照サイトのまま。

pkg update
pkg upgrade
termux-setup-storage
pkg install openssh
sshd
ip a

ただ、ip aを実行すると Cannot bind netlink socket: Permission denied と出たので、代わりに ifconfig を使いました。
その後、ユーザー名確認とパスワード設定をしました。

whoami
passwd

PCからTermuxにSSH接続

作業効率を上げるために、PCからTermuxにSSHで接続する。

ssh -p 8022 <ユーザー名>@<wlan0のアドレス>

これでPCからログインできるようになり、だいぶ作業が楽になります。Bluetoothキーボードがあるとさらに便利かも。

必要なツールもこのタイミングでインストールしました。

pkg install vim

公開鍵認証の設定

PC側ではすでに鍵を持っていたが、RSAが古かったのでこれを機に作り直した。

# PC側
ssh-keygen -t ed25519 # 必要なら鍵を生成
scp -P 8022 id_ed25519.pub <Termuxユーザー名>@<Termuxアドレス>:
# Termux側
mkdir ~/.ssh
cat ~/id_ed25519.pub >> ~/.ssh/authorized_keys

さらに、TermuxからPCへもログインできるように、逆方向の設定も行いました。

ショートカットからスクリプトを実行する設定

Termux:Widgetのインストール

ショートカットを作るために、GitHubからリリース版をインストールしました。
Termuxの~/.shortcuts/ディレクトリにスクリプトを配置します(なければ作成)。

mkdir -p ~/.shortcuts
cp your-script.sh ~/.shortcuts/
chmod +x ~/.shortcuts/your-script.sh
ホーム画面にウィジェットを追加

Androidのホーム画面にてウィジェットを追加する操作を行い、「Termux:Widget」を追加します。
「2x2」ではなく「1x1」の Termux shortcut を選ぶと、登録したスクリプトを個別にショートカットとして配置できます。
家のPCの電源を一括で落とす危険なスクリプトなので、Home画面の普段使わない面倒くさい場所にコッソリと置きました。

ショートカットをおいた場所
オリジナル画像リンク(139.86 KiB)

sshでシャットダウンを行うシェルスクリプト

最初はどのPCも同じ poweroff コマンドでいけると思ったのですが、結果的にPCごとに対応が必要でした。

#!/bin/bash

# XigmaNas
ssh user_name@address "poweroff" &
# Manjaro Linux
ssh -tt user_name@address "systemctl poweroff" &
# Windows
ssh user_name@address "shutdown /s /t 0" &

各OSごとの設定

XigmaNASの設定

特に何も考えずにsshdを起動したら、設定不足でうまく動きませんでした。Webインターフェースの「サービス→SSH」で「公開鍵認証を許可」にチェックを入れる必要がありました。

Manjaro Linuxの設定

苦戦して、色々と設定を触った結果、何が効いたのか分からない。最後に効果があったのは、 /etc/polkit-1/rules.d/50-nopasswd-poweroff.rules を追加して、wheelグループのユーザーがパスワード無しでsystemctl poweroffが実行できるようにした。

polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.login1.power-off" && subject.isInGroup("wheel")) {
        return polkit.Result.YES;
    }
});

Windowsの設定

sshdのインストール、sshdの立ち上げは省略。

鍵認証でログインできず苦戦しました。原因は、sshd_configの以下の設定で別のauthorized_keysを参照していたためでした。これをコメントアウトしたら解決しました。

Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

*1:スマホには全然興味がないです。

GitのベアリポジトリをNASに置くことにした

一人でソース管理しているし、正直ベアリポジトリなんて要らないと思ってた。でも、最近いじってたリポジトリでブランチが消せない事態に遭遇。幸い、最新の master は無事だったから問題はなかったけど、さすがにヒヤッとした。それで、保険としてGitのベアリポジトリを用意することにした*1。

GitHubのアカウントは今も作ってないので、代わりにXigmaNASにベアリポジトリを置いて運用する方針に決めた。

XigmaNASにGitを置こうとしたが

最初は「XigmaNASならGitくらい動くだろう」って軽く見てた。でも、実際はGitが入ってないし、無理やりインストールしようとしても容量不足で怒られる始末。仕方なく、NASをSMBでLinuxにマウントして、Linux上でGitを動かす形に落ち着いた。ファイルの実体はNAS上にあるから、多少はマシだろうという判断だ。

設定手順

NAS側の準備

Git用のユーザー(gituser)をXigmaNAS上に作成し、SMBで共有するGit用フォルダを設定した。

Linuxからマウント

作成した共有フォルダをLinux側からマウントする。以下のコマンドを使用した。noperm オプションはNAS側の権限で読み書きするために必要。

sudo mount -t cifs //XigmaNASのアドレス/git_share Linux側のマウント先 -o username=gituser,password=設定,noperm

ベアリポジトリの利用

mount後、普通にGitのベアリポジトリを作成し、 git push origin master が使えるように。
今のところ、 git push は頻繁には行わないので、不要になったらすぐに umount する運用にしている。

post-receiveの設定

念のため、 git push 後にキャッシュを書き出すように sync を行うだけの post-receive フックを設定した。ただ、これがどれだけ効果あるかは正直不明だ。

すべてのベアリポジトリに毎回 post-receive を書くのは手間だったので、Gitのテンプレート機能を活用することにした。テンプレートフォルダにフックの雛形 post-receive.sample を置いて、必要なときだけ名前を変えて使うようにした。

~/.git-templates/hooks/post-receive.sample を書いて

#!/bin/sh

sync

以下で、gitの設定にした。

git config --global init.templateDIR ~/.git-templates

XigmaNAS上のGig bearはWindowsからでも使えるか

ここまで設定しておいて、ふと「WindowsマシンからこのNASのベアリポジトリにアクセスできるのかな?」と不安になった。多分、SMBで共有できればWindowsからも使えるはず。自分のプログラムはマルチプラットフォーム対応のときもあり、Windowsでの動作確認や微調整ができると助かるんだよなぁ。

AI先生によるとネットワークパスでGit pull/pushは推奨しないそうなので、zドライブにマウントすることした。
さっそく、 git clone /z/my_projects/pomodoro.git とすると

fatal: detected dubious ownership in repository at 'Z:/my_projects/pomodoro.git'
'Z:/my_projects/pomodoro.git' is owned by:
        (inconvertible) (S-1-5-21-2768214786-1361613841-632331992-1000)
but the current user is:
        YYYYYYYY/XXXXX (S-1-5-21-3988748606-2148608539-3574766069-1001)
To add an exception for this directory, call:

        git config --global --add safe.directory Z:/my_projects/pomodoro.git
fatal: Could not read from remote repository.

と言ってくる。所有者の不一致と言ってくるので、エラーメッセージのまま git config を行うことで、git pullは出来た。
今、Windows上で動かす物はないので確認しなかったが、pullまでできればpush出来るでしょ。

*1:複数マシンで作業するときだけ、その場しのぎで同じフォルダにベアリポジトリを作ってた

Xremapをsystemdのユーザーサービスで管理することにした

Xremapがたまに落ちてしまって消えるのが面倒になったので、systemdのユーザーサービスとして動かすことにした。これなら自動で再起動もしてくれるので安心。

まず、 ~/.config/xremap/xremap.service を以下の内容で作成した。

[Unit]
Description=xremap service
After=graphical.target

[Service]
Restart=always
RestartSec=3
ExecStart=/usr/bin/xremap --watch=device /home/%u/.config/xremap/xremap_config.yaml --mouse

[Install]
WantedBy=default.target

設定ができたら、次のコマンドでユーザーサービスとして有効化&起動する。

systemctl --user enable ~/.config/xremap/xremap.service
systemctl --user start xremap.service

カササギ殺人事件

ミステリーチャレンジ、まだ続けてる。SFは好きだけどミステリーはそこまでだからか、凝りすぎてて刺さらない。これ、ドラマだったら面白そうなのにな。

XMonadとSteam

なんとなく、xmonadが最近変わってないかなと思って、xmonad-contrib 0.18.1のリリースノートを今更見てみた。すると、こんな記述を発見。

Requests for unmanaged windows no longer cause a refresh. This avoids flicker and also fixes disappearing menus in the Steam client and possibly a few other client applications.

(See also XMonad.Hooks.FloatConfigureReq and/or XMonad.Util.Hacks for additional Steam client workarounds.)

これを試してみたら、確かに動きが改善された気がする。スクリーンモードもボーダーレスで表示できるようになったし。

それ以外にも、以前からの変更点は以下です。

  • mod-Alt-j/k でウィンドウの高さを伸縮できる
  • Steamのちらつき問題が改善された
  • 擬似的なドロップダウンターミナルを実現した。ついでに、urxvtをデーモン化した

設定が増えちゃったけど、まあ仕方ないよね。

Steamアプリでボーダーレスしている光景
オリジナル画像リンク(688.62 KiB)


xmonad.hs(2024年11月時点)

import System.Exit
import XMonad
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.FloatConfigureReq (fixSteamFlicker)
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.SetWMName
import XMonad.Layout.ResizableTile
import qualified XMonad.StackSet as W
import XMonad.Util.EZConfig
import XMonad.Util.NamedScratchpad
import XMonad.Util.Run
import XMonad.Util.SpawnOnce
import XMonad.Util.WorkspaceCompare

main = do
    xmonad $
        ewmhFullscreen . ewmh $
            docks $
                addEwmhWorkspaceSort (pure myFilter) $
                    def
                        { terminal = "urxvtc"
                        , modMask = mod4Mask
                        , borderWidth = 3
                        , workspaces = ["1", "2", "3", "4"]
                        , startupHook = myStartupHook
                        , manageHook = myManageHook
                        , layoutHook = myLayoutHook
                        , handleEventHook = myHandleEventHook
                        }
                        `removeKeysP` ["M-S-q"]
                        `additionalKeysP` myKeys

myManageHook =
    myManageHookFloat
        <+> manageDocks
        <+> namedScratchpadManageHook scratchpads
        <+> manageHook def

myKeys =
    [ ("M-S-p", spawn "xfce4-appfinder --disable-server")
    , ("M-S-b", sendMessage ToggleStruts)
    , ("M-C-M1-q", io (exitWith ExitSuccess))
    , ("M-M1-j", sendMessage MirrorShrink)
    , ("M-M1-k", sendMessage MirrorExpand)
    , ("M-S-r", dualMonitorSwitch)
    , ("M-s", namedScratchpadAction scratchpads "terminal")
    ]

myStartupHook = do
    spawnOnce "urxvtd -o -f"
    spawnOnce "xremap ~/.config/xremap_config.yaml --mouse"
    mapM_ spawnOnce ["tint2", "copyq", "fcitx5", "pasystray"]
    spawnOnce "sh ~/bin/mysetup.sh"
    setWMName "LG3D" -- Javaアプリケーションの問題を回避

myLayoutHook = avoidStruts $ ResizableTall 1 (3 / 100) (1 / 2) [] ||| Full

myManageHookFloat =
    composeAll
        [ className =? "Xfce4-appfinder" --> doFloat
        , className =? "Pomodoro" --> doFloat
        , className =? "copyq" --> doFloat
        , className =? "steam" --> doShiftSilent "3"
        , className =? "Vivaldi-stable" --> doShiftSilent "3"
        , resource =? "scratchpad" --> defaultFloating
        ]

myHandleEventHook =
    fixSteamFlicker <+> handleEventHook def

-- ディスプレイ0にワークスペース1を出力し,ディスプレイ1にワークスペース2を出力
dualMonitorSwitch :: X ()
dualMonitorSwitch = do
    screenWorkspace 0 >>= flip whenJust (windows . W.view)
    (windows . W.greedyView) "1"
    screenWorkspace 1 >>= flip whenJust (windows . W.view)
    (windows . W.greedyView) "2"

-- ワークスペースを切り替えずにアプリを移動する
doShiftSilent :: WorkspaceId -> ManageHook
doShiftSilent = doF . W.shift

-- Scratchpad の設定
scratchpads :: [NamedScratchpad]
scratchpads =
    [ NS "terminal" "urxvtc -fn \"xft:Migu 1M:size=8\" -name scratchpad +sb" (resource =? "scratchpad") defaultFloating
    , NS "xterm" "xterm -rv" (className =? "XTerm") defaultFloating
    ]
myFilter = filterOutWs [scratchpadWorkspaceTag]

ファイルの暗号化にopensslを使う(2024年末)

ファイルを暗号化する際、ポータビリティを重視してopensslを使い続けている。
ただ、ここ3年ほどコマンドを変更していないので、そろそろ古くなっていないか気になり、見直してみた。
その結果、ハッシュ関数をSHA-256からSHA-512に変更したほうが良さそうだと判断し、設定を変えた。

これからは、しばらくこの新しい設定で暗号化・復号化をしていく予定。

openssl aes-256-cbc -e -salt -pbkdf2 -md sha512 -in 入力ファイル名 -out 出力ファイル名
openssl aes-256-cbc -d -salt -pbkdf2 -md sha512 -in 入力ファイル名 -out 出力ファイル名

Xremapでトラックボールのボタンを割り当てる

xremapを使い始めて、xbindkeysで設定していたトラックボールのボタン割り当ても一緒にまとめられるんじゃないかと思って試してみた。それと、ついでにキーボードのマルチメディアボタンもちゃんと動くように設定しておいた。

xremap ~/.config/xremap_config.yaml --mouse

xremap_config.yamlに書いた内容

modmap:
  - name: SandS
    remap:
      Space: [Shift_L, Space]
  - name: MenuKey2SUPER_R
    remap:
       KEY_COMPOSE: [SUPER_R, KEY_COMPOSE]
  - name: ZenHan-ESC
    remap:
       KEY_KATAKANAHIRAGANA: KEY_ESC
       KEY_ESC: KEY_ZENKAKUHANKAKU

keymap:
  - name: Huge Track Ball
# Left button:    BTN_LEFT
# Right button:   BTN_RIGHT
# Tilt Wheel:     BTN_MIDDLE
# Tilt left:      unknown key 59987/59999
# Tilt Right:     unknown key 59986/59998
# Forward button: BTN_EXTRA
# Back button:    BTN_SIDE
# Fn1:            BTN_FORWARD
# Fn2:            BTN_BACK
# Fn3:            BTN_TASK
    remap:
      BTN_TASK: CTRL-W
    device:
       only: ['ELECOM TrackBall Mouse HUGE TrackBall']
  - name: Keyboard Volume Control
    remap:
      KEY_VOLUMEUP:
        launch: ["pactl", "set-sink-volume", "@DEFAULT_SINK@", "+3dB"]
      KEY_VOLUMEDOWN:
        launch: ["pactl", "set-sink-volume", "@DEFAULT_SINK@", "-3dB"]
      KEY_MUTE:
        launch: ["pactl","set-sink-mute", "@DEFAULT_SINK@", "toggle"]
  - name: Caps2BS
    remap:
      CapsLock: KEY_BACKSPACE
      Shift-CapsLock: CapsLock