2026年09月12日

Ubuntu のバックアップ:QNAP 側にトラブル発生

 「Ubuntu で Time Machine 的なバックアップ」で書いたバックアップは、最近まで順調に進んでいたのですが、ここ数日失敗するようになってしまいました。途中でタイムアウトになってしまうのです。調べてみたところ、QNAP 本体のバックアップ先のディスクが満杯になっていました。

20260912-1.png

 QNAP のハードディスクが壊れた時に備えて、QNAP に USB 接続でもう1つハードディスクをつなぎ、HBS3 アプリを使ってバックアップしています。このアプリが、本体側で削除済みのファイル・ディレクトリをそのまま残してしまっているようです。また、ハードリンクをサポートしていないため、ハードリンクで同一ファイルを表しているエントリをすべて別ファイルとしてコピーしてしまっているようです。まあ、一般のユーザーでそんなことをする人は少数派でしょうから、HBS3 アプリがハードリンクをサポートしていなかったとしても、文句を言う筋合いはありません。自力でやりな、ということですよね。

 ということで、自力でやります。Linux のバックアップ対象フォルダに対しては、HBS3 によるバックアップ対象から外して、自前の rsync スクリプトを cron で回します。QNAP の cron の書き方には癖があって、普通に crontab で編集すると、再起動のときに消えてしまうそうです。こちらに解説があるのですが:

QNAP Systems, Inc. - ネットワーク接続ストレージ(NAS)

How to add jobs to crontab to schedule a job

Applicable Products QTS and QuTS Hero Solution You must be able to connect to you QNAP NAS using SSH and know how to edit a file ...

 これでも、システムアップデートのときに消えてしまうことがあるようです(Gemini談)。そこで、/share 配下のストレージ(要はハードディスク)の方に rsync のスクリプトと crontab 設定用のスクリプトを両方書いておいて、起動時に crontab 設定を自動実行する、という作戦でいきます。

 まず、rsync のスクリプトです。二重起動を避けるため、PIDファイルを使ってプロセスの生存チェックをしています。また、ログローテーションの機能も自前で書いてあります。(chmod +x で実行可能にしておく)

[/share/LinuxBackups/qnap-backup/myrsync.sh]
#!/bin/bash
SCRIPT_DIR="/share/LinuxBackups/qnap-backup"
LOG_DIR="${SCRIPT_DIR}/logs"
LOG_NAME="myrsync"
MAX_BACKUPS=9
PID_FILE="${SCRIPT_DIR}/${LOG_NAME}.pid"

# Check if PID file exists
if [ -f "$PID_FILE" ]; then
  PID=$(cat "$PID_FILE")
  # Check if the process with that PID is actually running
  if kill -0 "$PID" 2>/dev/null; then
    echo "$(date): Script is already running with PID $PID. Exiting." >> "${LOG_DIR}/${LOG_NAME}.log"
    exit 1
  else
    # The script crashed last time and left a stale PID file
    echo "$(date): Stale PID file found ($PID), but process is dead. Cleaning up." >> "${LOG_DIR}/${LOG_NAME}.log"
    rm -f "$PID_FILE"
  fi
fi

# Create PID file and register cleanup on exit
echo $$ > "$PID_FILE"
trap 'rm -f "$PID_FILE"; exit' INT TERM EXIT

# 1. Delete the oldest log if it exists (myrsync.9.log)
if [ -f "${LOG_DIR}/${LOG_NAME}.${MAX_BACKUPS}.log" ]; then
  rm "${LOG_DIR}/${LOG_NAME}.${MAX_BACKUPS}.log"
fi
# 2. Shift existing backups (8 -> 9, 7 -> 8, ..., 1 -> 2)
for i in $(seq $((MAX_BACKUPS - 1)) -1 1); do
  if [ -f "${LOG_DIR}/${LOG_NAME}.${i}.log" ]; then
    mv "${LOG_DIR}/${LOG_NAME}.${i}.log" "${LOG_DIR}/${LOG_NAME}.$((i + 1)).log"
  fi
done
# 3. Rotate the current log to .1.log
if [ -f "${LOG_DIR}/${LOG_NAME}.log" ]; then
  mv "${LOG_DIR}/${LOG_NAME}.log" "${LOG_DIR}/${LOG_NAME}.1.log"
fi
# 4. Do rsync backup
rsync -aHAX --numeric-ids --info=progress2 --recursive --delete --force --stats --sparse  "/share/LinuxBackups/snapshots/" "/share/Dev1Partition1/LinuxBackups/snapshots/" >"${LOG_DIR}/${LOG_NAME}.log" 2>&1

 次に、crontab 設定用のスクリプトです。(これも chmod +x で実行可能にしておく)

[/share/LinuxBackups/qnap-backup/setup-cron.sh]
#!/bin/sh
CRON_LINE="0 2 * * * /share/LinuxBackups/qnap-backup/myrsync.sh"
if ! grep -q "myrsync.sh" /etc/config/crontab; then
  echo "$CRON_LINE" >> /etc/config/crontab
  crontab /etc/config/crontab
  /etc/init.d/crond.sh restart
fi

 自動実行の設定をします。QNAP の管理ページに Web 経由でログインして、「コントロールパネル>システム>ハードウェア」を開き、「起動時にユーザー定義処理を実行」にチェックを入れます。

20260912-2.png

 次に autorun.sh を作成しますが、これがちょっと難しい。以下のページに解説があるのですが、「TS-x28の場合」の説明の通りにやっても、「/dev/mmcblk0p7 does not exist」と断られます。その下にある「init」スクリプトを使うやり方でいきます。

$ /etc/init.d/init_disk.sh mount_flash_config
$ vi /tmp/nasconfig_tmp/autorun.sh
/bin/bash /share/LinuxBackups/qnap-backup/setup-cron.sh
$ chmod +x /tmp/nasconfig_tmp/autorun.sh
$ ls -l /tmp/nasconfig_tmp
total 52
-rwxr-xr-x 1 admin administrators    57 2026-09-12 22:28 autorun.sh*
drwx------ 2 admin administrators 16384 2009-08-25 15:29 lost+found/
-rw-r--r-- 1 admin administrators  8666 2026-07-26 10:07 smb.conf
-rw-r--r-- 1 admin administrators    11 2026-07-26 10:07 smb.conf.cksum
-rw-r--r-- 1 admin administrators    37 2020-10-25 19:12 system.map.key
-rw-r--r-- 1 admin administrators  8708 2026-07-26 10:07 uLinux.conf
$ /etc/init.d/init_disk.sh umount_flash_config

 先ほどのコントロールパネルの画面で「autorun.shを開く」をクリックすると、書き込んだスクリプトを確認することができます。

20260912-3.png

 動作確認です。

$ crontab -l | grep myrsync
(何も出力なし)
$ /tmp/nasconfig_tmp/autorun.sh
Stopping periodic command scheduler: crond.
Starting periodic command scheduler: crond.
$ crontab -l | grep myrsync
0 2 * * * /share/LinuxBackups/qnap-backup/myrsync.sh

 しばらくこれで運用して、様子を見ます。バックアップは、安定して動くようになるまで、試行錯誤が必要ですね。

タグ:Linux
Posted at 2026年09月12日 23:49:15

2026年09月10日

Ubuntu での開発環境:VSCode + wxWidgets

 Ubuntu でもアプリの開発環境を立ち上げてみました。IDE としては、無難なところで VSCode を選びました。Mac でも Python とか Javascript 開発で一応使った経験はあります。Linux だからといって emacs や vim を使うほどの超ガチ勢ではないので、まあこんなところでしょう。

Visual Studio Code - The open source AI code editor | Your home for multi-agent development

 VSCode は公式サイトから deb ファイルをダウンロードしてきてインストールします。Discover で探すと snap 版が見つかるのですが、これには「日本語が入力できない」という致命的な欠点があります。

【Ubuntu22.04】VSCodeで日本語が入力できない場合の対処法 - Qiita

日本語でコメントを書きたい 私は Visual Studio Code でC++やPythonを書いています。 OSをUbuntu20.04から22.04にアップデートしたところ、日本語入力ができなくなったのでメモ。 ちなみにブラウザの検索窓など、VSCode以外ではちゃ...

 とりあえずやってみたいこととして、wxWidgets/C++ でアプリが書けるようにします。Linux でアプリ開発をするといっても、今から GTK や Qt をイチから覚えるのはちょっとキツい。また、一時 wxLua やら wxPython にも手を出したのですが、使い捨てのツールならともかく、公開して他人でも使えるモノにしようとすると、いろいろ問題が出てきます。最終的には、ネイティブバイナリにコンパイルできるのが最強です。その点では、一番確実なのは wxWidgets のネイティブ言語である C++ ですね。

 VSCode がまだよくわかってないので、いろいろ試行錯誤しました。今のところ、こんな環境に落ち着きつつあります。

1. VSCode の機能拡張として、C/C++ Extension, CMake Tools をインストールする。

 C/C++ Extension は当然でしょう。この機会に make から cmake に移行しようと思っているので、CMake Tools を入れました。

2. Linux の開発環境を整える。

$ sudo apt install build-essential cmake git libwebkit2gtk-4.1-dev

 最後の libwebkit2gtk-4.1-dev は、wxWebView を使うのに必要です。Linux における libwebkit2gtk の互換性問題はなかなかややこしいことになっていますが、その話はまたの機会に。

3. wxWidgets を自前でビルドして、静的ライブラリを作っておく。

 アプリ開発のプロジェクトディレクトリは $HOME/Development/wxMyProjects/{プロジェクト名} と決めておきます。リンクする wxWidgets のバージョンを確実に特定するため、自前でビルドして、$HOME/Development/wxMyProjects/extlibs 以下にインストールしておきます。

$ curl -L https://github.com/wxWidgets/wxWidgets/releases/download/v3.2.11/wxWidgets-3.2.11.tar.bz2 >wxWidgets-3.2.11.tar.bz2
$ tar xfj wxWidgets-3.2.11.tar.bz2
$ cd wxWidgets-3.2.11
$ mkdir build-linux-temp; cd build-linux-temp
$ ../configure --disable-shared --with-opengl --enable-monolithic --disable-sys-libs --prefix=$HOME/Development/wxMyProjects/extlibs 2>&1 | tee configure.log
$ make -j 4 2>&1 | tee make.log
$ make install 2>&1 | tee install.log
$ make distclean

4. プロジェクトフォルダのルートに CMakePresets.json を作成する

 せっかく wxWidgets で書くんだったら、同じプロジェクトで Linux, Mac, Windows のどれでもビルドできるようにしたいところです。使うコンパイラの種類(Linux は g++, Mac は clang++)、デバッグ/リリースビルドの区別、作業用ディレクトリの場所などを決めておくため、CMakePresets.json を使ってプリセットを定義します。(とりあえず Linux と Mac 用です。Windows は後で考えます)

{
  "version": 3,
  "cmakeMinimumRequired": {
    "major": 3,
    "minor": 20,
    "patch": 0
  },
  "configurePresets": [
    {
      "name": "linux-base",
      "hidden": true,
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/${presetName}"
    },
    {
      "name": "linux-gxx-debug",
      "inherits": "linux-base",
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Linux"
      },
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "CMAKE_C_COMPILER": "gcc",
        "CMAKE_CXX_COMPILER": "g++"
      }
    },
    {
      "name": "linux-gxx-release",
      "inherits": "linux-base",
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Linux"
      },
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",
        "CMAKE_C_COMPILER": "gcc",
        "CMAKE_CXX_COMPILER": "g++"
      }
    },
    {
      "name": "macos-base",
      "hidden": true,
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/${presetName}",
      "cacheVariables": {
        "CMAKE_C_COMPILER": "clang",
        "CMAKE_CXX_COMPILER": "clang++"
      }
    },
    {
      "name": "macos-debug",
      "inherits": "macos-base",
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Darwin"
      },
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug"
      }
    },
    {
      "name": "macos-release",
      "inherits": "macos-base",
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Darwin"
      },
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    }
  ],
  "buildPresets": [
    {
      "name": "build-linux-debug",
      "configurePreset": "linux-gxx-debug"
    },
    {
      "name": "build-linux-release",
      "configurePreset": "linux-gxx-release"
    },
    {
      "name": "build-macos-debug",
      "configurePreset": "macos-debug"
    },
    {
      "name": "build-macos-release",
      "configurePreset": "macos-release"
    }
  ]
}

5. CMakeLists.txt を作る。

 まだよくわかってないんですが、あちこち調べたり Google Gemini に教えてもらったりしながら、ここまでたどり着きました。

cmake_minimum_required(VERSION 3.20)  #  使うcmakeのバージョン
project(firstapp)                     #  プロジェクトの名前
set(EXTLIBS "$ENV{HOME}/Development/wxMyProjects/extlibs")   #  extlibs のパス
                                      #  他の依存ライブラリも同じ場所に置く予定
set(wxWidgets_CONFIG_EXECUTABLE "${EXTLIBS}/bin/wx-config")  #  FindwxWidgets のために wx-config の位置を指定
find_package(wxWidgets REQUIRED COMPONENTS core base)  #  wxWidgets を見つける
include(UsewxWidgets)                          #  wxWidgets を使うのに必要なフラグを設定
set(SOURCES MyApp.cpp)                         #  ソースファイルを列挙(ここでは1つだけ)
if(APPLE)
add_executable(FirstApp MACOSX_BUNDLE ${SOURCES})  #  Mac のアプリケーションバンドルの作成を指示
else()
add_executable(FirstApp ${SOURCES})            #  実行ファイルの作成を指示
endif()
target_compile_features(FirstApp PUBLIC cxx_std_17)  #  コンパイルフラグ
target_link_libraries(FirstApp PRIVATE ${wxWidgets_LIBRARIES})  #  wxWidgets のライブラリを追加
set_target_properties(FirstApp PROPERTIES OUTPUT_NAME "MyApplication")   #  実行ファイルの名称を指定

6. MyApp.cpp を作る。

 例えば下のようなものです。

#include <wx/wx.h>

class MyApp : public wxApp {
public:
    virtual bool OnInit();
};

class MyFrame : public wxFrame {
public:
    MyFrame(const wxString& title);
};

bool MyApp::OnInit() {
    MyFrame *frame = new MyFrame(_T("最小のwxWidgetsアプリ"));
    frame->Show(true);
    return true;
}

MyFrame::MyFrame(const wxString& title)
    : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(400, 300)) {
}

wxIMPLEMENT_APP(MyApp);

7. VSCode で開く。

 上記の3つのファイルを含んだディレクトリを VSCode で開きます。最初に、一番上の行に "Restricted Mode is intended for safe code browsing."という表示が出ます。このままだと読み出しのみで変更ができないため、Manage を押して、"Trust" を指示します。

20260910-1.png

 すると、「構成の事前設定を選択してください (Select a configure preset)」というメニューが出て、CMakePresets.json の "configurePresets" に書いたプリセットを選ぶように促されます。最初は debug を選びます。

20260910-2.png

 このメニューは、VSCode から別のアプリに移ると消えてしまいます。そのときは、VSCode の左のカラムにある CMake Tools のアイコンを選び、「構成」(Configuration) のリストを開いて、右端のえんぴつマークを押すと、同じメニューが現れます。

20260910-3.png

 Configuration を選ぶと、CMakeLists.txt がチェックされます。ここでエラーが出た場合は、何か問題があると思われるので、頑張って解決します。エラーがなくなったら、画面一番下の「Build」を押すとビルドが始まります。ここもきっとエラーが出るので、頑張って解決します。エラーがなくなったら、虫のアイコンを押すと、デバッガ (gdb) 上での実行が始まります。

20260910-4.png

 ここから先は、Xcode などでの開発と同じなので、特筆すべきことはありません。CMakeLists.txt の書き方を頑張って覚えなくちゃな、というところです。

20260910-5.png
タグ:Linux wxWidgets
Posted at 2026年09月10日 22:56:25

2026年09月09日

Ubuntu 上の KVM/QEMU-Windows で共有フォルダを設定する

 先日設定した KVM/QEMU 上の Windows ですが(「Ubuntu 上の KVM/QEMU で Windows 11 を走らせる」)、Ubuntu 側とディスク共有を設定したいところです。VMWare では GUI で簡単に設定できたのですが、けっこう手間がかかりました。

 まず、Ubuntu 側に virtiofsd をインストールします。

$ sudo apt install virtiofsd

 共有するフォルダを作成します。ホームディレクトリの .vmshare としました。隠しフォルダにした理由はあとで書きます。

 次に、仮想マシン側の設定です。Windows をシャットダウンして、仮想マシンマネージャの「表示」から「詳細」を選ぶと、仮想マシンの設定画面になります。

20260908-3.png

 「メモリ」を開いて「共有メモリを有効にする」にチェックを入れます。これを先にやっておかないと virtiofs ファイルシステムを追加できないようです。

20260908-1.png

 「ハードウェアを追加」から「ファイルシステム」を追加します。ドライバーは「virtiofs」、ソースパスは ~/.vmshare(フルパスで書く), ターゲットパスは vmshare とします。ソースパスが共有される Ubuntu 上のフォルダで、ターゲットパスは Windows 上で見える名前です。

20260908-2.png

 設定を保存して、仮想マシン上で Windows を起動します。WinFspをインストールします(https://winfsp.dev/rel/)。

20260908-4.png

 Windowsツールの「サービス」を起動します。

20260908-5.png

 「VirtIO FS Service」を探し、「プロパティ」を開きます。「スタートアップの種類」を「自動」とし、「サービスの状態」の「開始」を押して「実行中」状態にします。

20260908-6.png

 エクスプローラーを開くと、ドライブZ:に共用フォルダがマウントされています(ドライブレターは環境依存)。

20260908-7.png

 2つ以上のフォルダを共有したいときは、さらにもう一手間かける必要があります。WinFsp は virtio ディスクを1つしかマウントできないため、Ubuntu 側で Bind マウントという機能を使って、ディレクトリをマウントします。次のようにすると、~/Downloads の内容が .vmshare/Downloads の中に、~/Development/wxMyProjects の内容が .vmshare/wxMyProjects の中に、それぞれ見えるようになります。

$ mkdir $HOME/.vmshare/Downloads
$ sudo mount --bind $HOME/Downloads $HOME/.vmshare/Downloads
$ mkdir $HOME/.vmshare/wxMyProjects
$ sudo mount --bind $HOME/Development/MyProjects $HOME/.vmshare/MyProjects

 永続的にマウントするには、/etc/fstab に下のように追記します。

/home/tnagata/Downloads /home/tnagata/.vmshare/Downloads none bind 0 0
/home/tnagata/Development/wxMyProjects /home/tnagata/.vmshare/wxMyProjects none bind 0 0

 なお、Bind マウントしたディレクトリは、ファイルシステムの中で二重に存在していることになるので、バックアップ対象から外しておきます。また、Ubuntu 側の普段使いで混乱しないように、隠しフォルダに入れるようにしました。

 これで、Windows から2つの共有フォルダが見えるようになりました。

20260908-8.png
タグ:Linux
Posted at 2026年09月09日 00:09:53
email.png