第11章 システムメンテナンス(ソースビルド・バックアップ・利用者通知)

LPIC-2 206.1〜206.3 相当

201試験パートの最後に、日常的な運用に欠かせないバックアップと、システムメンテナンスの基本操作を扱います。バックアップは「取得すること」自体が目的ではなく、実際に「復元できること」が本当のゴールである点を意識しながら学習を進めましょう。

バックアップの基本戦略

方式特徴
フルバックアップすべてのデータを毎回バックアップ。復元は簡単だが容量・時間がかかる
差分バックアップ前回のフルバックアップ以降の変更分のみ。復元にはフル+最新の差分の2つが必要
増分バックアップ前回のバックアップ(フルまたは増分)以降の変更分のみ。容量は最小だが復元に全世代が必要

それぞれの方式にはトレードオフがあります。差分バックアップは復元に必要なファイル数が少なく手順がシンプルですが、フルバックアップからの経過日数が長くなるほど1回あたりの差分バックアップのサイズが大きくなっていきます。増分バックアップはバックアップ自体のサイズを常に最小に保てますが、復元時にはフルバックアップから最新の増分まで、すべての世代を正しい順序で適用する必要があり、途中の世代が1つでも欠けると復元に失敗します。実務では、週次でフルバックアップ、日次で増分バックアップを取得するといった組み合わせがよく使われます。

3-2-1ルール: バックアップ戦略の目安として広く知られているのが「3-2-1ルール」です。データは3つ以上のコピーを持ち、2種類以上の異なるメディア(例: ローカルディスクとテープ、またはクラウド)に保存し、そのうち1つは物理的に離れた場所(オフサイト)に置く、という考え方です。火災や盗難など、拠点全体に影響する災害への備えになります。

バックアップ計画を立てる際は、RPO(Recovery Point Objective:どの時点の状態まで復旧できればよいか、つまり許容できるデータ損失量)とRTO(Recovery Time Objective:障害発生からどれだけの時間で復旧できればよいか)という2つの指標を意識すると、必要なバックアップ頻度と方式を具体的に決めやすくなります。たとえば「RPOは1時間」という要件であれば、少なくとも1時間おきの増分バックアップが必要になります。

よくある間違い: バックアップを取得すること自体に満足してしまい、実際にリストア(復元)できるかどうかを一度も検証しないまま運用してしまうケースは非常に多く見られます。バックアップメディアの破損、取得スクリプトの設定ミス、権限不足など、いざという時に復元できない原因は様々です。定期的にリストア訓練を行い、復元手順が実際に機能することを確認しておく必要があります。

tarによるアーカイブ作成と増分バックアップ

tar は複数のファイルを1つのアーカイブにまとめるコマンドで、シンプルなバックアップスクリプトでも今なお現役です。--listed-incremental オプションを使うと、前回からの変更分だけを記録した増分バックアップも作成できます。

$ tar czf full-2024-01.tar.gz --listed-incremental=snapshot.snar /home/user/   # -vなしのため正常時は無出力
# 初回はフルバックアップとして取得し、snapshot.snarに状態を記録
$ tar czf incr-2024-02.tar.gz --listed-incremental=snapshot.snar /home/user/   # 正常時は無出力
# 2回目以降は同じsnapshot.snarを参照し、変更分だけをアーカイブ
$ tar xzf full-2024-01.tar.gz -C /restore/     # 展開して復元(正常時は無出力)
$ tar xzf incr-2024-02.tar.gz -C /restore/     # フル展開後に増分アーカイブも同じ場所へ展開し、上書き・追記していく(正常時は無出力)

この行のこの値に注目: これらのコマンドは-v(verbose)を付けていないため成功時は無出力です。処理内容を画面で確認したい場合はtar czvfのようにvを追加すると、アーカイブに含めたファイル名が1行ずつ表示されます。

増分バックアップから復元する際は、フルバックアップを展開した後、増分バックアップを取得した順番どおりに1つずつ展開していく必要があります。--listed-incrementalで記録された増分アーカイブには、削除されたファイルの情報も含まれるため、正しい順序で復元すればファイルの削除も再現されます。順序を誤ると、古いファイルで新しいファイルを上書きしてしまうなど、意図しない状態になる危険があるため注意してください。

ddによるディスクイメージの取得

dd は、ファイルシステムを意識せずディスクやパーティションをブロック単位でそのまま複製するコマンドです。OS丸ごとのイメージ取得や、起動用USBメディアの作成にも使われます。

$ sudo dd if=/dev/sda of=/mnt/backup/sda.img bs=4M status=progress
21474836480 bytes (21 GB, 20 GiB) copied, 62 s, 346 MB/s
5000+0 records in
5000+0 records out
21474836480 bytes (21 GB, 20 GiB) copied, 62.0341 s, 346 MB/s
# /dev/sda全体をイメージファイルとして保存。bsでブロックサイズを指定すると高速化できる

この行のこの値に注目: status=progressを付けると、コピー完了を待たずに現在までの転送量と速度がリアルタイムで更新表示されます。最終行のrecords in/records outの数が一致していれば、読み取ったブロックと書き込んだブロックの数に食い違いがなかったことを確認できます。

危険なコマンド: ddは if=(入力)と of=(出力)を取り違えると、既存のデータを一瞬で破壊してしまいます。実行前には必ずデバイス名を lsblk で確認する習慣をつけましょう。

不良セクタのある古いディスクからイメージを取得する場合、既定のddはエラーが発生した時点で停止してしまいます。conv=noerror,syncオプションを付けると、読み取りエラーが起きても処理を継続し、読めなかった部分をゼロで埋めて(syncオプション)ブロック位置のずれを防ぎながら、可能な限り多くのデータを救出できます。

$ sudo dd if=/dev/sda of=/mnt/backup/sda.img bs=4M conv=noerror,sync status=progress
dd: error reading '/dev/sda': Input/output error
15032385536 bytes (15 GB, 14 GiB) copied, 48 s, 313 MB/s
5000+0 records in
5000+0 records out
21474836480 bytes (21 GB, 20 GiB) copied, 71.2201 s, 301 MB/s
# 読み取りエラーを無視して継続し、破損データはゼロ埋めして続行する(データ救出向けの設定)

この行のこの値に注目: error reading ...: Input/output errorという行が、実際に不良セクタで読み取りエラーが発生した箇所です。conv=noerror,syncを指定しているため処理はそこで止まらず、最終的にrecords inとrecords outが一致した状態で完了しています(読めなかった部分はゼロ埋めされてブロック位置がずれていません)。

rsync — 効率的なファイル同期

rsync は、変更された差分だけを転送する効率的な同期コマンドで、ローカル間だけでなくSSH経由でリモートサーバーとも同期できます。バックアップスクリプトの定番です。

$ rsync -av /home/user/docs/ /mnt/backup/docs/
sending incremental file list
report.docx
notes.txt

sent 1,234,567 bytes  received 35 bytes  822,668.00 bytes/sec
total size is 1,234,200  speedup is 1.00
# -a: 属性を保持したまま再帰的にコピー, -v: 詳細表示
$ rsync -avz -e ssh /home/user/docs/ user@backupserver:/backup/docs/
sending incremental file list
report.docx

sent 456,789 bytes  received 22 bytes  91,362.20 bytes/sec
total size is 1,234,200  speedup is 2.70
# -z: 転送時に圧縮, -e ssh: SSH経由で転送
$ rsync -av --delete /src/ /dst/
sending incremental file list
deleting old-report.docx
report.docx

sent 1,234,600 bytes  received 58 bytes  493,863.20 bytes/sec
total size is 1,234,200  speedup is 1.00
# --delete: コピー元にないファイルをコピー先からも削除し、完全に同期する

この行のこの値に注目: sending incremental file listの下に列挙されるのは、今回実際に転送されたファイルだけです(変更のないファイルは表示されません)。--deleteを付けた場合はdeleting ...という行で削除されたファイルも確認でき、speedupの値が大きいほど、差分転送によって全量コピーより効率化できていることを示します。

覚えておきたい注意点: コピー元のパスの末尾に / を付けるかどうかで動作が変わります。docs/ は「docsの中身」を、docs(スラッシュなし)は「docsディレクトリ自体」を転送先にコピーします。

本番データに対して実行する前には、--dry-run(-n)オプションを付けて、実際にはコピーせずにどのファイルが転送・削除の対象になるかを事前確認する習慣をつけると安全です。また、帯域が限られた回線でのバックアップでは--bwlimit=1000(単位はKB/秒)のように転送速度を制限し、業務時間中の通信を圧迫しないようにすることもできます。

$ rsync -av --delete --dry-run /src/ /dst/
sending incremental file list
deleting old-report.docx
report.docx

sent 1,234 bytes  received 22 bytes  2,512.00 bytes/sec
total size is 1,234,200  speedup is 982.42 (DRY RUN)
# --dry-run: 実際には転送・削除を行わず、対象となるファイルの一覧だけを表示する

この行のこの値に注目: 出力自体は通常実行時とほぼ同じ形式ですが、最後に(DRY RUN)という注記が付き、実際には何も転送・削除されていないことを示します。表示されたdeleting ...の一覧に想定外のファイルが含まれていないかを確認してから、--dry-runを外して本実行します。

cronと組み合わせた自動バックアップ

# 毎日午前2時にバックアップを実行(crontab -eで設定)
0  2  *  *  *  rsync -av /home/ /mnt/backup/home/ >> /var/log/backup.log 2>&1
よくある間違い: cronで定期実行するバックアップスクリプトのログ出力先を >>(追記)のまま放置してしまうと、ログファイルが際限なく肥大化し、いずれディスク容量を圧迫してしまいます。logrotateと組み合わせてログを定期的にローテーション・圧縮・削除する設定もあわせて行うのが実務での基本です。また、バックアップ先のディスク自体の空き容量も監視しておかないと、バックアップが「実行はされているが実際には失敗し続けている」状態に気づかないまま放置されるリスクがあります。

圧縮アーカイブの展開とファイル形式の判定

パッケージマネージャーに存在しないソフトウェアは、ソースコードから自分でビルドすることがあります。ソースコードは通常.tar.gz・.tar.bz2・.tar.xzのような圧縮アーカイブとして配布され、圧縮方式によって展開時に指定するtarのオプションが異なります。

拡張子圧縮方式展開オプション個別の展開コマンド
.tar.gz / .tgzgziptar xzfgunzip
.tar.bz2bzip2tar xjfbunzip2
.tar.xzxztar xJfunxz
$ tar xzf myapp-1.2.3.tar.gz    # gzip圧縮のアーカイブを展開(-zがgzip、-xが展開、-fでファイル指定。-vなしのため正常時は無出力)
$ tar xjf myapp-1.2.3.tar.bz2   # bzip2圧縮の場合は-j(正常時は無出力)
$ tar xJf myapp-1.2.3.tar.xz    # xz圧縮の場合は-J(正常時は無出力)

圧縮方式ごとにオプションを覚えるのが面倒な場合、tarの-a(--auto-compress)オプションを使うと、ファイル名の拡張子から圧縮方式を自動判別してくれます。

$ tar xaf myapp-1.2.3.tar.xz    # -aにより拡張子から圧縮方式を自動判別して展開(正常時は無出力)

ダウンロードしたファイルの拡張子が不明・不正確な場合や、実際の中身を確認したい場合はfileコマンドで実際のファイル形式を判定できます。

$ file myapp-1.2.3.tar.gz
myapp-1.2.3.tar.gz: gzip compressed data, from Unix, original size modulo 2^32 1234567

fileコマンドはファイルの拡張子ではなく、ファイル先頭のマジックナンバー(形式ごとに決まった固有のバイト列)を見て中身を判定するため、拡張子が改変・欠落していても正しい形式を判定できます。

豆知識: tar単体では圧縮を行わず、あくまで複数ファイルを1つにまとめる(アーカイブ化する)だけです。-z/-j/-Jのオプションは、tarの処理の前後にそれぞれgzip/bzip2/xzのフィルタを噛ませて自動的に圧縮・展開を行わせているに過ぎません。

ソースツリーの配置とREADME・INSTALLの確認

展開したソースコードは、システム全体で共有する用途であれば慣習的に/usr/src/以下に置きます。個人の検証・作業用であれば、ホームディレクトリ配下の作業用ディレクトリで済ませても問題ありません。どちらの場合も、複数バージョンのソースを混在させないよう、バージョン番号を含んだディレクトリ名のまま作業するのが基本です。

$ cd /usr/src/
$ sudo tar xzf /tmp/myapp-1.2.3.tar.gz   # 正常時は無出力
$ cd myapp-1.2.3

ビルドを始める前に、必ずアーカイブに含まれるREADMEとINSTALLファイルに目を通しましょう。READMEにはソフトウェアの概要や依存ライブラリの一覧が、INSTALLにはそのプロジェクト固有のビルド手順や、標準的な手順から外れる注意点が記載されていることが多く、これらを確認せずに定型的な手順をいきなり実行すると、依存関係の不足などでビルドが途中で失敗しやすくなります。

GNU Autotoolsによるビルド設定(./configure)

多くのオープンソースソフトウェアは、GNU Autotoolsという仕組みで生成されたconfigureスクリプトを同梱しています。このスクリプトは、ビルドを行う環境(コンパイラの種類、利用可能なライブラリ、OSの種類など)を検査し、その環境に合わせたMakefileを生成する役割を持ちます。

$ ./configure --help | head -20
`configure' configures myapp 1.2.3 to adapt to many kinds of systems.

Usage: ./configure [OPTION]... [VAR=VALUE]...

Configuration:
  -h, --help              display this help and exit
      --prefix=PREFIX     install architecture-independent files in PREFIX
                          [default: /usr/local]
      --sysconfdir=DIR    read-only single-machine data [PREFIX/etc]

Optional Features:
  --disable-debug         disable debug build
Optional Packages:
  --with-ssl              enable OpenSSL support
# そのソフトウェア固有のオプション一覧を表示

この行のこの値に注目: [default: /usr/local]のように、各オプションの既定値がヘルプに明記されています。--with-/--enable-系のオプション名を実行前にここで確認しておくと、後述のビルドオプション指定でタイプミスによる失敗を防げます。

./configure --helpを実行すると、標準的なオプションに加えて、そのソフトウェア固有の機能を有効・無効化するオプションが一覧表示されます。主要なオプションは次のとおりです。

オプション意味
--prefix=パスインストール先のルートディレクトリ(既定では多くの場合/usr/local)
--exec-prefix=パスアーキテクチャ依存のファイル(実行ファイルなど)のインストール先。既定では--prefixと同じ
--sysconfdir=パス設定ファイルのインストール先(既定では--prefix配下のetc)
--with-<feature>特定の外部ライブラリ・機能を使うように指定する
--without-<feature>特定の外部ライブラリ・機能を使わないように指定する
--enable-<feature>ソフトウェア自身が持つオプション機能を有効にする
--disable-<feature>ソフトウェア自身が持つオプション機能を無効にする

--with-/--without-は主に外部ライブラリとの連携(例:--with-sslでOpenSSL連携を有効にする)に、--enable-/--disable-はそのソフトウェア自身が実装している機能の取捨選択(例:--disable-debugでデバッグビルドを無効にする)に使われる傾向がありますが、どちらの接頭辞を使うかは各プロジェクトの裁量に委ねられており、厳密な使い分けのルールがあるわけではありません。

$ ./configure --prefix=/usr/local --sysconfdir=/etc --with-ssl --disable-debug
checking for gcc... gcc
checking whether the C compiler works... yes
checking for OpenSSL... yes
checking for a BSD-compatible install... /usr/bin/install -c
config.status: creating Makefile
config.status: creating config.h

この行のこの値に注目: 各行のchecking for ... yesが、必要なコンパイラやライブラリが正しく検出されたことを示します。最後にconfig.status: creating Makefileが表示されれば、この後のmakeに必要なMakefileが正常に生成された合図です。

config.logの読み方

configureが「エラーが発生しました」とだけ表示して終了した場合、その具体的な原因は同じディレクトリに生成されるconfig.logに記録されています。

$ tail -30 config.log
configure:3421: checking for OpenSSL
configure:3450: gcc -o conftest conftest.c -lssl -lcrypto
conftest.c:1:10: fatal error: openssl/ssl.h: No such file or directory
configure: failed program was:
| #include <openssl/ssl.h>

この行のこの値に注目: この例では、configureがOpenSSLのヘッダファイル(openssl/ssl.h)を見つけられずに失敗しています。ライブラリ本体(.soファイル)がインストール済みであっても、コンパイルに必要なヘッダファイルや.soへのシンボリックリンクを含む開発用パッケージが別途インストールされていないと、このようなエラーが発生します。Debian系ではlibssl-dev、RHEL系ではopenssl-develのように、開発用パッケージには-dev/-develという接尾辞が付くのが慣習です。

$ sudo apt install libssl-dev      # Debian系(Ubuntu 24.04 LTSの例)
Reading package lists... Done
The following NEW packages will be installed:
  libssl-dev
Setting up libssl-dev:amd64 (3.0.13-0ubuntu3.5) ...
$ sudo dnf install openssl-devel   # RHEL系(Rocky Linux 9の例)
Installed:
  openssl-devel-1:3.2.2-1.el9.x86_64
Complete!

この行のこの値に注目: aptはSetting up ...、dnfはInstalled: ... Complete!で完了を示します。インストール後に再度./configureを実行すると、先ほど失敗していたchecking for OpenSSLの行がyesに変わっているはずです。

よくある間違い: エラーメッセージの末尾だけを見て「原因不明のエラー」と諦めてしまうケースが多く見られます。configureのエラーは大抵の場合、config.logの該当箇所(checking for 〜が失敗している行の直後)に具体的なコンパイルエラーが記録されているため、まずconfig.logを確認する習慣をつけましょう。

makeによるビルドとインストール

configureが生成したMakefileを元に、実際のコンパイル・インストールを行うのがmakeコマンドです。Makefileは、「ターゲット」「依存関係」「レシピ」の3要素からなるルールの集合で構成されています。

Makefileの基本構造(簡略化した例)
myapp: main.o utils.o
	gcc -o myapp main.o utils.o

main.o: main.c
	gcc -c main.c

この行のこの値に注目: 1行目のmyapp: main.o utils.oが「ターゲット: 依存関係」で、「myappを作るにはmain.oとutils.oが必要」という意味です。次の行(タブでインデントされた行)が「レシピ」で、依存関係を満たした際に実行される実際のコマンドです。makeは、ターゲットより依存ファイルの更新日時が新しい場合にのみ、そのレシピを再実行するという仕組みで、変更のなかったファイルの再コンパイルを省略し、ビルド時間を短縮しています。

$ make                 # 既定のターゲット(通常はall)をビルド
gcc -c main.c
gcc -c utils.c
gcc -o myapp main.o utils.o
$ make -j$(nproc)      # CPUのコア数分だけ並列にコンパイルジョブを実行し、ビルドを高速化
gcc -c main.c
gcc -c utils.c
gcc -c parser.c
gcc -o myapp main.o utils.o parser.o

この行のこの値に注目: makeは実行した各コンパイルコマンド(gcc -c ...)をそのまま画面に表示します。-j$(nproc)を付けた場合は複数のコンパイルが同時に走るため、表示される行の順序が実行のたびに前後することがあります。

make -j$(nproc)の$(nproc)は、そのマシンの論理CPUコア数を返すコマンド置換です。-jオプションに数値を指定しない場合は無制限に並列実行しようとするため、メモリ不足を招く危険があります。コア数に応じた妥当な並列数を明示的に指定するのが安全です。

ターゲット意味
all既定のビルド対象一式をコンパイルする(多くの場合、makeを引数なしで実行した際のターゲット)
installビルドした成果物をシステムにインストールする
uninstallinstallでインストールしたファイルを削除する(すべてのプロジェクトが用意しているとは限らない)
cleanビルドで生成された中間ファイル(.oファイルなど)を削除する
distcleancleanの対象に加え、configureが生成したMakefileなど、配布状態に戻すためのファイルまで削除する
check / testビルドしたソフトウェアのテストスイートを実行する
$ make check            # インストール前にテストスイートを実行し、正しくビルドできているか確認
PASS: test-parser
PASS: test-io
============================================================================
Testsuite summary for myapp 1.2.3
============================================================================
# TOTAL: 2
# PASS:  2
# FAIL:  0
============================================================================
$ sudo make install     # システムにインストール
/usr/bin/install -c myapp /usr/local/bin/myapp
/usr/bin/install -c -m 644 myapp.1 /usr/local/share/man/man1/myapp.1
$ make clean             # 中間ファイルを削除(configureの結果は残る。正常時は削除対象がなければ無出力に近い)
rm -f myapp main.o utils.o
$ make distclean         # configureの結果も含めて配布時の状態に戻す
rm -f myapp main.o utils.o
rm -f Makefile config.h config.status config.log

この行のこの値に注目: make checkの# FAIL: 0行がテスト全件成功の確認ポイントです。ここに1件でも失敗があれば、インストール前にソースの問題を疑うべきサインになります。make install実行時のinstall -c ...行から、実際にどのファイルがどこへ配置されたかを確認できます。

いきなり本番環境の/usr/local以下に直接インストールする前に、一時的な別ディレクトリへインストールし、内容を確認してから本来の場所へ配置したい場合はDESTDIR変数を使います。

$ make install DESTDIR=/tmp/myapp-stage   # make installと同様、install -c ...の実行ログが表示される
# /tmp/myapp-stage/usr/local/... のように、指定したパスを先頭に付けた場所へインストールされる
$ find /tmp/myapp-stage -type f    # 実際にどこへ何がインストールされるかを事前に確認できる
/tmp/myapp-stage/usr/local/bin/myapp
/tmp/myapp-stage/usr/local/share/man/man1/myapp.1

この行のこの値に注目: findの結果が、実際にシステムへ反映される前の「予行演習」の全ファイル一覧です。想定外の場所(例えば/etc直下など)にファイルが生成されていないかをここで確認してから、本番の/usr/local以下にコピーするかどうかを判断します。

DESTDIRは--prefixとは異なり、Makefile自体が対応している場合にのみ機能する仕組みです。すべてのインストールパスの先頭に指定したディレクトリを仮想的に付け足すだけで、ソフトウェア自身が内部で使う実際のパス(--prefixで指定した値)は変わりません。この性質を利用して、パッケージ管理システム(rpmやdebのビルドプロセス)は、いったんDESTDIRで指定した仮のルートにインストールしてから、その中身をパッケージファイルとして固めるという手法を広く使っています。

installコマンドによる個別ファイルの配置

Makefileのinstallターゲットの内部では、多くの場合cpではなくinstallコマンドが使われています。installは、ファイルのコピーとあわせて、パーミッション設定・所有者変更・必要なディレクトリの自動作成までを1コマンドで行える点がcpとの違いです。

オプション意味
-m モードコピー先ファイルのパーミッションを指定する(例:-m 755)
-o 所有者コピー先ファイルの所有者を指定する(root権限が必要)
-g グループコピー先ファイルの所有グループを指定する
-Dコピー先の親ディレクトリが存在しない場合、自動的に作成してからコピーする
$ sudo install -m 755 -o root -g root -D myapp /usr/local/bin/myapp   # 正常時は無出力
# /usr/local/bin/ が存在しなくても自動作成し、実行権限755・所有者root:rootでコピーする

cpで同じことをしようとすると、事前にディレクトリの存在確認・作成、コピー、chmod、chownを個別のコマンドとして実行する必要があり、installコマンドはこれらを1行にまとめられる点でビルドスクリプト(Makefileのレシピ)との相性がよく、多くのプロジェクトで採用されています。

patchによるソースコードの修正適用

ソースコードに独自の修正(バグ修正や機能追加)を加えたい場合、ソースファイル全体を書き換えるのではなく、変更差分だけを記述したパッチファイルを作成・適用するのが一般的です。パッチファイルはdiff -uで生成します。

$ diff -u main.c.orig main.c > myfix.patch   # 正常時は無出力(差分はリダイレクト先のファイルに書き込まれる)
# myfix.patch の中身の例
--- main.c.orig	2026-08-20 10:00:00.000000000 +0900
+++ main.c	2026-08-21 09:00:00.000000000 +0900
@@ -10,7 +10,7 @@
     int ret = do_something();
-    if (ret != 0) {
+    if (ret < 0) {
         fprintf(stderr, "error
");
# -u(unified形式)は、前後数行の文脈込みで差分を表示する、最も広く使われる形式

この行のこの値に注目: ---/+++行が比較対象の2ファイル、@@ -10,7 +10,7 @@が「元ファイルの10行目から7行分、新ファイルの10行目から7行分」を意味する変更箇所の位置情報です。行頭の-が削除された行、+が追加された行を示します。

生成したパッチを適用するにはpatchコマンドを使いますが、パッチファイル内に記録されているファイルパスの階層をどこまで一致させるかを-pオプションで指定する必要があります。

オプション意味
-p0パッチファイル内のパスをそのまま使う(パスの先頭を一切削らない)
-p1パッチファイル内のパスの先頭ディレクトリを1階層分削ってから適用する

この行のこの値に注目: 多くのパッチファイルは、diff -u a/main.c b/main.cのように、比較対象のディレクトリにa/・b/という接頭辞を付けた形式(gitのdiff出力に多い形式)で生成されます。この場合、そのままの階層では現在のディレクトリにa/・b/というディレクトリは存在しないため、-p1を指定して先頭の1階層(a/やb/)を取り除いてから適用する必要があります。

$ patch -p1 --dry-run < myfix.patch
checking file main.c
# --dry-runで、実際にはファイルを変更せず適用可否だけを事前確認する
$ patch -p1 < myfix.patch
patching file main.c
# 事前確認で問題なければ、実際にパッチを適用する

この行のこの値に注目: --dry-run時はchecking file ...、実際の適用時はpatching file ...と表示が変わります。もし途中で当たらない箇所があるとFAILED at line ...という行と.rejファイルの生成を知らせるメッセージが追加で表示されます。

誤ってパッチを適用してしまった場合や、動作確認の結果パッチを取り消したい場合は-R(reverse)オプションで元に戻せます。

$ patch -p1 -R < myfix.patch    # 適用済みのパッチを取り消す(逆方向に適用)
patching file main.c

この行のこの値に注目: -Rを付けた場合も表示はpatching file ...のままなので、通常適用との違いは表示上は分かりません。取り消しが正しく行われたかは、diff main.c main.c.origのように元ファイルと再度比較して確認するのが確実です。

パッチの適用結果は、生成されるファイルの拡張子からも確認できます。

拡張子意味
.origパッチ適用前の元のファイルのバックアップ(バックアップオプションを付けた場合に生成される)
.rejパッチの一部がうまく適用できなかった場合に生成される、適用できなかった差分(reject)
注意: .rejファイルが生成された場合、パッチの一部(またはすべて)が対象ファイルに適用されなかったことを意味します。対象ソースコードのバージョンがパッチ作成時と異なる場合によく発生します。.rejファイルの中身を確認し、該当箇所を手作業で修正するか、対象ソースの正しいバージョンを入手し直す必要があります。

CMakeベースのプロジェクト

近年のプロジェクトでは、./configureの代わりにCMakeというビルドシステムジェネレータを使うケースが増えています。CMakeはconfigureと同様、環境を検査してMakefile(またはNinjaなど他のビルドツール向けのファイル)を生成する役割を担いますが、ソースディレクトリを汚さないよう、専用のビルド用ディレクトリを分けて作業するのが慣習になっています。

$ mkdir build && cd build
$ cmake ..                          # 1つ上のディレクトリ(ソースツリーのルート)を指定してMakefileを生成
-- The C compiler identification is GNU 13.2.0
-- Detecting C compiler ABI info - done
-- Configuring done (0.4s)
-- Generating done (0.1s)
-- Build files have been written to: /usr/src/myapp-1.2.3/build
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release
-- Configuring done (0.3s)
-- Generating done (0.1s)
-- Build files have been written to: /usr/src/myapp-1.2.3/build
# -Dオプションで各種変数を指定できる(--prefixに相当するのがCMAKE_INSTALL_PREFIX)
$ make -j$(nproc)
[ 33%] Building C object CMakeFiles/myapp.dir/main.c.o
[ 66%] Building C object CMakeFiles/myapp.dir/utils.c.o
[100%] Linking C executable myapp
$ sudo make install
-- Install configuration: "Release"
-- Installing: /usr/local/bin/myapp

この行のこの値に注目: cmakeの--で始まる行は生成処理の進捗ログで、最終行のBuild files have been written to: ...でMakefile一式の生成が完了したことが分かります。make実行時の[100%]という表記は、autotoolsのMakefileと異なりCMake生成のMakefileに特徴的な進捗パーセンテージ表示です。

この「ソースディレクトリの外に専用のビルドディレクトリを作る」流儀はout-of-source buildと呼ばれ、ビルドディレクトリごと削除するだけでいつでもクリーンな状態に戻せる、複数の設定(DebugビルドとReleaseビルドなど)を別々のディレクトリで同時に保持できるといった利点があります。

checkinstallによるパッケージ化

すでに触れたとおり、make installで直接インストールしてしまうと、パッケージマネージャーの管理下に入らないため、後からの削除やバージョン確認が困難になります。checkinstallは、この問題を解決するツールです。

$ sudo checkinstall
This package will be built according to these values:
0 -  Maintainer: [ root@web01 ]
1 -  Summary: [ Package created with checkinstall ]
2 -  Name:    [ myapp ]
3 -  Version: [ 1.2.3 ]
4 -  Release: [ 1 ]
5 -  License: [ GPL ]
9 -  Architecture: [ amd64 ]

Enter a number to change any of them or press ENTER to continue:
...
**********************************************************************

 Done. The new package has been installed and saved to

 /usr/src/myapp-1.2.3/myapp_1.2.3-1_amd64.deb

**********************************************************************

この行のこの値に注目: 実行途中で表示されるパッケージ情報(バージョン・アーキテクチャなど)はEnterキーでそのまま進めるか、番号を入力して修正できます。最終的に生成された.deb(RHEL系では.rpm)ファイルのパスが末尾に表示され、これがdpkg -i/apt removeで管理できるパッケージです。

checkinstallは、実際には指定されたインストールコマンド(既定ではmake install)を実行しつつ、その過程でシステムに書き込まれるファイルを監視し、その結果を1つのパッケージファイル(.debや.rpm)にまとめます。生成されたパッケージは通常のパッケージ管理コマンドでインストールされるため、apt removeやdnf removeで綺麗にアンインストールできるようになり、ソースビルドの「管理外になってしまう」という弱点を補えます。

ldconfigと共有ライブラリの認識

ソースからビルドした共有ライブラリ(.soファイル)を/usr/local/libのような標準外の場所にインストールした場合、そのライブラリに依存する実行ファイルを起動しようとしても「共有ライブラリが見つからない」というエラーで失敗することがあります。これは、実行時に共有ライブラリを検索する場所のキャッシュに、新しいライブラリの情報がまだ反映されていないためです。

$ myapp
myapp: error while loading shared libraries: libmyapp.so.1: cannot open shared object file: No such file or directory

このエラーを解消するには、ライブラリの検索パスを設定ファイルに追加したうえで、キャッシュを再生成する必要があります。

/etc/ld.so.conf.d/myapp.conf(新規作成)
/usr/local/lib
$ sudo ldconfig                 # /etc/ld.so.conf.d/以下の設定を反映し、共有ライブラリのキャッシュ(/etc/ld.so.cache)を再構築(正常時は無出力)
$ ldconfig -p | grep myapp     # 再構築後のキャッシュに、目的のライブラリが登録されたか確認
	libmyapp.so.1 (libc6,x86-64) => /usr/local/lib/libmyapp.so.1

この行のこの値に注目: ldconfig -pの結果にライブラリ名と実際のパス(=> /usr/local/lib/...)が表示されていれば、動的リンカが正しく認識している状態です。この行が表示されない場合、/etc/ld.so.conf.d/の設定ファイルの記述漏れや、ldconfigの実行忘れを疑います。

ldconfigは、/etc/ld.so.confおよびそこからincludeされる/etc/ld.so.conf.d/*.confに列挙されたディレクトリを走査し、見つかった共有ライブラリの情報を/etc/ld.so.cacheというバイナリ形式のキャッシュファイルに記録します。実行時のライブラリ検索(動的リンカld.soによる処理)はこのキャッシュを参照するため、新しいライブラリを標準外の場所に配置した後は、必ずldconfigを実行してキャッシュを更新する必要があります。

実務のヒント: 一時的に環境変数LD_LIBRARY_PATHでライブラリの検索パスを追加する方法もありますが、これはそのシェルセッション・プロセスだけに限定的に効く一時的な回避策です。恒久的にシステム全体で認識させたい場合は、/etc/ld.so.conf.d/への設定ファイル追加とldconfigの実行が正しい手順です。

バックアップの整合性検証

取得したバックアップアーカイブが転送中や保存中に破損していないかを確認するには、チェックサム(ハッシュ値)を比較する方法が確実です。

$ sha256sum full-2024-01.tar.gz > full-2024-01.tar.gz.sha256   # 正常時は無出力(結果はリダイレクト先のファイルに書き込まれる)
# バックアップ取得直後にハッシュ値を記録しておく
$ sha256sum -c full-2024-01.tar.gz.sha256
# 後日、バックアップ先で改めて計算し、記録した値と一致するか検証する
full-2024-01.tar.gz: OK

特にテープやオフサイトのクラウドストレージなど、長期間手を触れないメディアに保存する場合、ビットロット(記録媒体の経年劣化によるデータの静かな破損)が発生していないかを定期的にチェックサムで検証しておくことが望ましいとされます。

3-2-1ルールという考え方

バックアップ戦略を設計するうえで広く知られている指針に「3-2-1ルール」があります。データを合計3つのコピーとして持ち、そのうち2種類の異なる媒体(例:ローカルディスクとテープ、あるいはローカルとクラウドストレージ)に保存し、そのうち1つは物理的に離れた場所(オフサイト)に置く、という原則です。すべてのバックアップを同じサーバーの別ディスクに置いているだけでは、火災や盗難、ランサムウェアによる暗号化被害など、そのサーバー自体に及ぶ災害・攻撃で全滅してしまう可能性があります。「バックアップを取っている」という事実だけでなく、「どんな障害シナリオに耐えられる構成になっているか」まで意識して設計することが、真に意味のあるバックアップ戦略につながります。

リストア訓練の重要性

バックアップ運用で見落とされがちなのが、「実際に復元できるかどうか」の検証です。取得自体は正常に完了していても、いざ復元しようとした際にアーカイブが壊れていた、必要な設定ファイルが取得対象から漏れていた、復元手順自体を誰も把握していなかった、といった事態は珍しくありません。定期的に本番とは別の検証環境へリストアを実際に行ってみる「リストア訓練」を実施し、復元にかかる時間(RTO:目標復旧時間)や、どこまでのデータ損失を許容できるか(RPO:目標復旧時点)を実測・見直しておくことが、バックアップを「本当に使える保険」にするために欠かせません。

/etc/issueと/etc/issue.net — ログイン前のバナー

メンテナンス作業(今夜のバックアップ取得中の性能低下や、再起動を伴うアップデートなど)を計画している場合、ログイン中の利用者や、これからログインしようとする利用者に事前に知らせておくことも、システム管理者の重要な役割です。まず、ログイン前に表示されるバナーから見ていきましょう。ローカルコンソール、およびネットワーク経由のログインでは、ユーザー名・パスワードの入力を促す前に、それぞれ別のファイルの内容が表示されます。

ファイル表示されるタイミング
/etc/issueローカルコンソール(物理端末・仮想コンソール)のログインプロンプトより前
/etc/issue.netTelnetなど、ネットワーク経由のログインプロンプトより前

/etc/issueには、ホスト名や日付などを動的に埋め込むためのエスケープシーケンスを記述できます。

シーケンス意味
ホスト名
\lログイン中の端末名(tty)
\d現在の日付
\sOS名
カーネルのリリースバージョン
/etc/issue の例
\s 
 (
) (\l)
# 表示例: Linux 5.15.0-91-generic (server01) (tty1)
注意: sshdは既定では/etc/issue.netを自動的には表示しません。SSHログイン前にバナーを表示させたい場合は、/etc/ssh/sshd_configにBanner /etc/issue.netのように明示的にディレクティブを指定する必要があります。Telnetなど他のプロトコルとSSHとでは、バナー表示の仕組みが異なる点に注意してください。
/etc/ssh/sshd_config への追記
Banner /etc/issue.net

/etc/motd — ログイン後のメッセージ

/etc/motd(Message of the Day)は、ログイン成功後に表示されるファイルです。/etc/issue・/etc/issue.netがログイン前に表示されるのに対し、/etc/motdは認証が済んだユーザーだけに向けたメッセージという違いがあります。

$ sudo vi /etc/motd
本日22:00〜22:30、定期メンテナンスのためサービスが一時停止します。

Ubuntuなど一部のディストリビューションでは、/etc/motdを静的なファイルとして直接編集するのではなく、/etc/update-motd.d/以下に置かれた複数の実行可能スクリプトを、ログインのたびに番号順(00-header、10-help-textのようにファイル名の先頭に数字を持つ)に実行し、その出力をまとめて動的に/etc/motd相当の内容として生成する仕組みが採用されています。

$ ls /etc/update-motd.d/
00-header  10-help-text  50-motd-news  90-updates-available
$ cat /etc/update-motd.d/00-header
#!/bin/sh
printf "Welcome to %s
" "$(lsb_release -ds)"

この仕組みにより、システムの稼働時間・利用可能なアップデート件数・セキュリティ情報など、常に最新の状態を反映した内容をログインのたびに動的に表示できます。独自のお知らせを追加したい場合は、/etc/update-motd.d/に新しい実行可能スクリプト(例:/etc/update-motd.d/99-maintenance)を追加します。

ログインバナーに書くべきこと・書くべきでないこと

/etc/issue・/etc/issue.netのようにログイン前に表示される情報は、認証されていない第三者(攻撃者を含む)も閲覧できてしまう点に注意が必要です。

注意: OSの詳細なバージョン情報(カーネルバージョンやディストリビューション名など)をログイン前のバナーに含めていると、攻撃者がそのバージョンに存在する既知の脆弱性を狙って攻撃を仕掛けるための手がかりを与えてしまいます。公開サーバーでは、既定で有効になっているエスケープシーケンス入りのバナーを、システム情報を含まない簡素なメッセージに置き換えておくのがセキュリティ上の定石です。

一方で、ログイン前のバナーに、無断アクセスを禁止する旨の法的な警告文を掲載しておく運用は、多くの組織で行われています。「このシステムへのアクセスは許可されたユーザーに限られ、不正アクセスは法的措置の対象となる」といった趣旨の文言をあらかじめ表示しておくことで、不正アクセスが発覚した際の法的な立証や対応の根拠として利用できる場合があります。この点は法域によって扱いが異なるため、実際の文言や運用については組織の法務部門に確認することが望まれます。

wallによるブロードキャスト通知

wall(write all)は、現在ログイン中の全ユーザーの端末に、即座にメッセージを一斉送信するコマンドです。緊急のメンテナンス予告など、今すぐ全員に伝えたい場合に使います。

$ wall "システムは10分後に再起動します。作業中のファイルは保存してください。"
# 引数として直接メッセージを渡す方法
$ wall < announcement.txt
# ファイルの中身をメッセージとして送信する方法
$ echo "5分後に再起動します" | wall
# echoの出力をパイプで渡す方法

いずれの方法でも、ログイン中の全ユーザーの端末(開いている全ターミナル)に即座にメッセージが割り込み表示されます。宛先を選ぶことはできず、システム全体への一斉通知に限定される点に注意してください。

shutdownによる予告と/run/nologin

shutdownコマンドは、システムの停止・再起動を予約実行するコマンドで、実行時にログイン中の全ユーザーへ自動的に警告メッセージを送信する点が特徴です。

$ sudo shutdown -h +30 "メンテナンスのため30分後に停止します"
# -h(halt):30分後にシステムを停止。ログイン中のユーザーに自動的に警告が送信される
$ sudo shutdown -r now
# -r(reboot):即座に再起動
$ sudo shutdown -c
# 予約済みのshutdownをキャンセルする

shutdownを実行して予約が入ると、指定した時刻の5分前から、システムは新規ログインを自動的に拒否するようになります。これは、/run/nologin(ディストリビューションによっては/etc/nologin)というファイルが自動的に生成され、このファイルが存在する間、一般ユーザーのログインがPAMによって拒否される仕組みによって実現されています。

$ cat /run/nologin
システムは停止処理中のため、現在ログインできません。

この/run/nologinは、shutdown -cでキャンセルするか、実際にシステムが停止・再起動されることで自動的に削除されます。root権限を持つユーザーは、この制限があっても引き続きログインできる点も覚えておきましょう。

systemctlによる電源操作とshutdownとの関係

現在の主要ディストリビューションでは、電源操作はsystemctl経由でも実行できます。

systemctlサブコマンド動作
systemctl poweroffシステムをシャットダウン(電源断)する
systemctl rebootシステムを再起動する
systemctl haltCPUを停止するが電源は切らない(poweroffとの違いに注意)
systemctl suspendサスペンド(メモリに状態を保持したまま省電力状態に移行)する
systemctl hibernateハイバネート(メモリの内容をディスクへ退避してから電源を切る)する

実際のところ、伝統的なshutdownコマンドの多くの実装は、内部的にsystemdへ処理を委譲するラッパーとして動作しており、shutdown -h nowを実行すると、最終的にはsystemctl poweroff相当の処理が呼び出されます。shutdownコマンドがsystemctlにはない独自の価値を持つのは、時間指定による予約実行(+30のような相対時刻や特定時刻の指定)と、それに伴うログインユーザーへの自動警告・新規ログイン拒否(/run/nologin)の仕組みを備えている点です。systemctl poweroffのようなコマンドは即時実行のみで、これらの予告機能を持ちません。

豆知識: haltとpoweroffは似ていますが、historicalには「haltはCPUの動作を止めるだけで、実際に電源を切るかどうかはハードウェア次第(電源を切らないこともある)」「poweroffは明示的に電源断のACPI命令まで発行する」という違いがありました。現在のsystemd環境では、既定の設定では両者とも最終的に電源を切る点でほぼ同じ結果になりますが、コマンド名としての意味の違いは覚えておくとよいでしょう。

計画メンテナンスの実務的な進め方

ここまでに紹介した通知手段は、単体で使うのではなく、計画的なメンテナンス作業の各段階で組み合わせて使うのが実務での標準的な進め方です。

  1. 事前告知: 作業の数日〜1週間前に、影響範囲・作業予定時刻・想定されるダウンタイムをメールやチャット、あるいは/etc/motdで告知しておく。
  2. 直前告知: 作業開始の直前(例:30分前、10分前、5分前)に、shutdown -h +30 "..."のような予約コマンドやwallで、ログイン中のユーザーに具体的な残り時間を伝える。
  3. メンテナンスモードへの移行: Webサービスであればロードバランサーから切り離す、あるいはメンテナンスページに切り替えるなどして、新規のアクセス・処理の受け入れを止める。
  4. 作業: 計画したメンテナンス作業(アップデート適用、設定変更、ハードウェア交換など)を実施する。
  5. 検証: サービスが正常に復旧しているか、想定した変更が反映されているかを確認する。ログの確認や、簡易的な疎通確認(ヘルスチェック)を行う。
  6. 完了告知: 作業が完了しサービスが正常に戻ったことを、事前告知と同じ手段(メール・チャット・motdの更新など)で関係者に伝える。
実務のヒント: 直前告知の段階でshutdownコマンドを使っておくと、予約時刻が近づくにつれ自動的に警告メッセージの間隔が短くなり(残り時間が少なくなるほど頻繁に警告が表示される)、ユーザーへの周知漏れを減らせます。また、作業中に予期せぬトラブルで長引く場合は、shutdown -cで一度キャンセルしてから状況を再告知するといった柔軟な対応も検討しましょう。

確認クイズ

Q1. 復元に「フルバックアップ + 最新の差分」の2つだけで済むバックアップ方式はどれですか?

解説: 差分バックアップは前回のフルバックアップ以降の変更分をまとめて保存するため、復元にはフル+最新の差分の2つだけで済みます。

Q2. 変更された差分だけを効率的に転送し、SSH経由でのリモート同期にも使えるコマンドはどれですか?

解説: rsync は差分のみを転送する効率的な同期コマンドで、-e sshオプションでリモートサーバーとの同期にも使えます。

Q3. rsync -av --delete /src/ /dst/ の --delete オプションの効果はどれですか?

解説: --delete は、コピー先にのみ存在する(コピー元では削除された)ファイルを削除し、コピー元と完全に一致した状態に同期します。

Q4. ソースコードからソフトウェアをビルドする際の一般的な手順の順序として正しいものはどれですか?

解説: 一般的な流れは、環境検査とMakefile生成を行う ./configure、コンパイルする make、インストールする make install の順です。

Q5. configureスクリプトでインストール先のルートディレクトリを指定するオプションはどれですか?

解説: --prefixは、make installでファイルをインストールする先のルートディレクトリを指定する、最も基本的なconfigureオプションです。

Q6. ログイン中の全ユーザーの端末に、即座にメッセージを一斉送信するコマンドはどれですか?

解説: wallコマンドは、現在ログイン中の全ユーザーの端末にメッセージを即座に一斉送信します。

Q7. ログイン成功後に表示され、お知らせやメンテナンス予定の告知によく使われるファイルはどれですか?

解説: /etc/motd(Message of the Day)はログイン成功後に表示されるファイルです。/etc/issueはログイン前(パスワード入力画面より前)に表示されます。

Q8. myapp-1.2.3.tar.xzを展開する際に指定すべきtarのオプションはどれですか?

解説: xz圧縮のアーカイブは-J(大文字)で展開します。-zはgzip、-jはbzip2に対応します。

Q9. tarの-a(--auto-compress)オプションの効果はどれですか?

解説: -aを指定すると、tarはファイル名の拡張子(.gz/.bz2/.xzなど)から圧縮方式を自動的に判別して処理します。

Q10. fileコマンドがファイルの形式を判定する際に主に参照するものはどれですか?

解説: fileコマンドはファイル先頭のマジックナンバーを見て中身を判定するため、拡張子が改変・欠落していても正しい形式を判定できます。

Q11. configureスクリプトが失敗した際、具体的な原因が記録されているファイルはどれですか?

解説: configureの失敗原因は、同じディレクトリに生成されるconfig.logの該当箇所(checking for 〜が失敗している行の直後)に記録されています。

Q12. configureがヘッダファイル不足でエラーになった場合、多くのディストリビューションで追加インストールが必要となるパッケージの接尾辞はどれですか?

解説: コンパイルに必要なヘッダファイルなどを含む開発用パッケージには、Debian系で-dev、RHEL系で-develという接尾辞が付くのが慣習です。

Q13. make -j$(nproc)における$(nproc)が返す値はどれですか?

解説: nprocは論理CPUコア数を返すコマンドで、-jにこの値を渡すことでコア数に応じた並列ビルドができます。

Q14. makeのdistcleanターゲットが、cleanターゲットと比べて追加で行うことはどれですか?

解説: cleanは中間ファイル(.oファイルなど)のみを削除しますが、distcleanはconfigureの結果まで含めて配布時の状態に戻します。

Q15. make install DESTDIR=/tmp/stageのようにDESTDIRを指定する目的はどれですか?

解説: DESTDIRは、すべてのインストールパスの先頭に指定したディレクトリを仮想的に付け足す仕組みで、パッケージ管理システムのビルドプロセスでも広く使われています。

Q16. installコマンドがcpと比べて優れている点はどれですか?

解説: installは-m/-o/-g/-Dなどのオプションで、コピーとパーミッション設定・所有者変更・ディレクトリ作成を1コマンドにまとめられます。

Q17. diff -u a/main.c b/main.cの形式で生成されたパッチファイルを適用する際に指定すべきオプションはどれですか?

解説: a/・b/という接頭辞付きのパスで生成されたパッチは、-p1で先頭の1階層を取り除いてから適用する必要があります。

Q18. patchコマンドで、適用済みのパッチを取り消すオプションはどれですか?

解説: -R(reverse)オプションを付けると、適用済みのパッチを逆方向に適用し、元の状態に戻せます。

Q19. パッチの一部が対象ファイルにうまく適用できなかった場合に生成されるファイルの拡張子はどれですか?

解説: .rej(reject)ファイルは、パッチの一部または全部が適用できなかった場合に生成される、適用できなかった差分です。

Q20. 設定ファイル/etc/issueのエスケープシーケンスのうち、ホスト名を表すものはどれですか?

解説: \nはホスト名、\lは端末名、\dは日付を表すエスケープシーケンスです。

Q21. sshd経由のログインで/etc/issue.netの内容を表示させるために、sshd_configに追加すべきディレクティブはどれですか?

解説: sshdは既定では/etc/issue.netを自動的に表示しないため、Bannerディレクティブで明示的に指定する必要があります。

Q22. Ubuntuで/etc/motdの内容が/etc/update-motd.d/以下のスクリプトから動的に生成される仕組みの説明として正しいものはどれですか?

解説: /etc/update-motd.d/以下の実行可能スクリプトを、ログインのたびにファイル名の番号順に実行し、その出力をまとめて動的にmotd相当の内容として表示します。

Q23. ログイン前に表示される/etc/issueにOSの詳細なバージョン情報を含めるべきでない主な理由はどれですか?

解説: 詳細なバージョン情報をログイン前のバナーに含めると、そのバージョンの既知の脆弱性を狙う攻撃の手がかりを与えてしまいます。

Q24. shutdown -h +30を実行すると、指定時刻の5分前から自動的に作られるファイルはどれですか?

解説: /run/nologinが自動生成され、このファイルが存在する間、一般ユーザーの新規ログインがPAMによって拒否されます。

Q25. systemctl haltとsystemctl poweroffの伝統的な違いとして説明されるものはどれですか?

解説: historicalには、haltはCPUを停止するだけで電源を切るかどうかはハードウェア次第、poweroffは明示的に電源断の命令まで発行するという違いがありました。

Q26. 計画メンテナンスの実務的な進め方の一般的な順序として正しいものはどれですか?

解説: 事前告知で予定を周知し、直前告知で具体的な残り時間を伝え、メンテナンスモードへ移行してから作業・検証を行い、最後に完了告知を行うのが標準的な流れです。