20191127のLinuxに関する記事は11件です。

ハードディスクのデータを全消去する方法

今まで使用していたディスクを、次の人に申し送るのに、ディスクのデータを全消去して渡したい時があると思います。
そんなときに使えるのが、shred コマンドとなります。
自分の身の回りにいるエンジニアでも、知っている人がいませんでした。
とても便利なコマンドなので、覚えておくといいと思います。
システムが Linux でも Windows でも Mac でもデバイス指定するので、関係なく使えると思います。

対象のシステムに、CD/DVD ドライブがあれば、そこに、LiveOS を入れます。Fedora などは最適だと思います。

LiveOS が立ち上がったら、コンソールを立ち上げ、root になります。

$ sudo su -

デバイスを確認します。

# ls /dev

/dev/sda が、/dev/sda1 /dev/sda2 となっているものを全消去するなら、以下のコマンドを実行します。

# shred -v /dev/sda2
(かなり時間が必要)
# shred -v /dev/sda1
(かなり時間が必要)
# shred -v /dev/sda
(boot loader を消してくれる)

shred コマンドは、デフォルトで 3回実行してくれます。
終了したら、CD/DVD を抜いて、マシンを再起動してみてください。

すっきり、気持ちいいですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Power SystemsでもKubernetesを使う!

Linux on Powerだとx86となにか違うの?

基本的にPowerでもx86と同じです。
ただ、当然ながらx86のイメージはPowerでは動かないので、アーキテクチャに合わせたイメージが必要になります。
その点だけ気をつければ、x86と同じように使えます。
なお、Power SystemsからインターネットへのアクセスにProxyが必要な環境で使っている皆様が多いかと思いますので、この記事ではProxyを使った手順をご紹介したいと思います。

構成

ここでは、1つのノードだけで動作するKubernetes(シングル・マスター・クラスター)をkubeadmコマンドを使って構成します。
わたしは以下の環境でトライしました。

OS: RHEL 7.6 LE
Memory: 4GB
CPU: 2コア (POWER8)
ストレージ: 50GB

Proxyの設定

とりあえず、.bashrcとか.bash_profileで以下の環境変数を設定しておきます。
自ノードへのアクセスのためにNO_PROXYをきちんと設定しておかないと、あとでハマります。

export http_proxy="http://10.91.0.1:8080"
export https_proxy="http://10.91.0.1:8080"
export ftp_proxy="http://10.91.0.1:8080"
export proxy="http://10.91.0.1:8080/"
export NO_PROXY="localhost,10.91.XX.XX"
export no_proxy="localhost,10.91.XX.XX"

Dockerの導入

下記のRedHatのドキュメントを参考にDockerを入れました。

Getting Docker in RHEL 7
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html-single/getting_started_with_containers/index#getting_docker_in_rhel_7

yum install docker device-mapper-libs device-mapper-event-libs
systemctl start docker.service
systemctl enable docker.service

DockerにもProxyの設定をしておきます。

mkdir -p /etc/systemd/system/docker.service.d
vi /etc/systemd/system/docker.service.d/http-proxy.conf
http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://10.91.0.1:8080/" "NO_PROXY=10.91.xx.xx/16"

docker daemonを再起動し、docker infoでプロキシーが設定されていることを確認します。

systemctl daemon-reload
systemctl restart docker
docker info

今更ですが、firewallは停止しておきます。
下記忘れましたが、SELinuxもpermissiveかdisableにしてます。

systemctl disable firewalld
systemctl stop firewalld
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

swapも無効にしておきます。

sudo swapoff -a

/etc/fstabの編集も忘れずに。

UUID=d06071e3-4760-4d1b-98d3-891566cbf0c3 / ext4 defaults 0 0
#/swap.img      none    swap    sw      0       0

Kubernetesの導入

Kubernetes導入のためのレポジトリを追加します。

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-ppc64le
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
EOF

kubelet、kubeadm、kubectlを導入します。

yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable --now kubelet

kubeadmを使ってkubernetesの構成を行います。
最初は、dry-runをしてエラーがないことを確認した後、本番にのぞみましょう。
"--pod-network-cidr="は、kubernetesクラスター内で使うCIDRを指定します。

kubeadm init --pod-network-cidr=192.168.0.0/16 --dry-run
kubeadm init --pod-network-cidr=192.168.0.0/16

成功すると、以下のような出力を得られます。
この情報は、後でKubernetesにアクセスするために使うので、大切に保存しておきます。

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.91.133.55:6443 --token 5yu18p.kf9k01j8ndzfbok4 \
    --discovery-token-ca-cert-hash sha256:d6e4c68bcc8347e71d946dbc7992c474c17170ce262cc9fa36b3dc980cd887f1

早速、kubernetesにadminでアクセスするために、~/.kube/configをコピーしてきます。

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

初期状態では、マスターノードにはPodが置かれないようにtaintされているため、taintを解除します。

kubectl get node
kubectl describe node <自ノード>
kubectl taint nodes <自ノード> node-role.kubernetes.io/master:NoSchedule-

以上でkubernetesが使える状況になりました。

Calicoの導入

複数ノードで使うときは、CNIを導入する必要があります。
以下にCalicoを導入したときの手順を紹介します。

kubectl apply -f \
https://docs.projectcalico.org/v3.8/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml

kubectl apply -f \
https://docs.projectcalico.org/v3.8/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calicoctl.yaml

参考文献

kubeadmを使用したシングルマスタークラスターの作成
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

Creating a single master cluster with kubeadm
https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/

Installing Calico for policy and networking
https://docs.projectcalico.org/v3.10/getting-started/kubernetes/installation/calico

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

シェルスクリプトでディレクトリ移動を自動化したぞ!

Webアプリを作ってるとき毎回起動するときdocker-composeでコンテナ立ち上げるのめんどくさいので自動化しました。

  • 使用OS centOS7
  • ライブラリ laradock
  1. ルート直下にディレクトリを分かりやすいように作ってその中に touch docker_compose_start.sh というファイルを作成
docker_compose_start.sh
#!usr/bin/bash

cd /project/laradock
docker-compose start

  1. 実行できるようにファイルの権限を変える

    chmod 755 docker_compose_start.sh

  2. 作ったディレクトリの中でファイルを実行する
    ./docker_compose_start.sh

これでコマンド一回でコンテナが立ち上がるようになる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Linuxコマンド】ファイルの作成と閲覧

はじめに

こちらは、KPI 項目A:「ターミナル・コマンドに慣れる」項目A:「ターミナル・コマンドに慣れる」のアウトプット記事です。

出会い

学生時代は、Ubuntuを講義で触っていたが、
血反吐を吐くくらい嫌いだった。

「地味だし見えねえし何してんのか分からねえ。ウケる。」という感じ。

そんな記憶のまま、
先日、Linuxコマンドをバシバシ叩く案件に参加することとなった。

最近は先輩に教えて頂きながら、
ターミナルでコマンドをバシバシ叩いている。

--- 少しだけ、楽しくなってきた。 ---

そんな人間が気に入ったLinuxコマンドを書いていくぜ。

本編

touch

本来はタイムスタンプを更新するためのコマンド。

しかし、今のところファイル作るためにしか使っていない。

# ファイルが作れる
$ touch ito-manager.timecard   #上司
$ touch tanaka-member.timecard #部下

こうすれば、部下のタイムカードを改竄することだって出来る。

# タイムスタンプを操作する
$ touch -t "201911271730" tanaka-member.timecard 
$ ls -ltr *.timecard
-rw-r--r--  1 n***********i  staff  0 11 27 17:30 tanaka-member.timecard
-rw-r--r--  1 n***********i  staff  0 11 27 20:20 ito-manager.timecard

cat

ファイルの中身を標準出力で表示するコマンド。
中身が多いと標準出力が圧迫されて、お葬式になる。

$ cat wagahai-ha-cat.book
吾輩は猫である
夏目漱石
 吾輩わがはいは猫である。名前はまだ無い。
...

image01.png

head/tail

ファイルを先頭または末尾から行数や文字数を限定して出力する。

まさに、頭と尻だけを出すためのコマンド。
「頭隠して尻隠さず」のことわざに立ち向かいたいときにおすすめ。

# タイトルと作者の先頭2行だけが知りたい人向け
$ head -n 2 wagahai-ha-cat.book
吾輩は猫である
夏目漱石

# オチの最後2行だけで全て分かる人向け
# 最後の1行は改行
$ tail -n 2 wagahai-ha-cat.book
 次第に楽になってくる。苦しいのだかありがたいのだか見当がつかない。水の中にいるのだか、座敷の上にいるのだか、判然しない。どこにどうしていても差支さしつかえはない。ただ楽である。否いな楽そのものすらも感じ得ない。日月じつげつを切り落し、天地を粉韲ふんせいして不可思議の太平に入る。吾輩は死ぬ。死んでこの太平を得る。太平は死ななければ得られぬ。南無阿弥陀仏なむあみだぶつ南無阿弥陀仏。ありがたいありがたい。

おまけ

clear

標準出力をキレイキレイするコマンド。
おきのどくですが 標準出力は きえてしまいました:scream:

$ clear

まとめ

記事のテイストをいつもと変えてみた。

Linuxコマンドも地味に楽しい。

スクリプト言語には、相性もいい気がする。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Linux SSH

今度は安全リモート通信のSSHについて書きます。

AWSの中で行うので、実際に行うには準備をお願いします。

SSH

離れた場所にあるサーバの中で作業を行いたい場合に
暗号や認証の技術を利用して
安全にリモートコンピュータと通信するためのプロトコルのことです。

リモート

離れた場所にあるサーバのことを「リモートサーバ」や「リモート環境」、省略して「リモート」と呼びます。

ローカル

自身のコンピュータを「ローカルサーバ」や「ローカル環境」、省略して「ローカル」と言います。

SSHのメリット

  • 通信を盗聴危険性を回避して、安全操作
  • サーバ上でのファイル操作、設定ファイルの編集ができる
  • バックアップを要する時、サーバ上で圧縮(ZIP)して、ファイルの一括ダウンロードできるので時間短縮ができる

SSHでログイン

リモートサーバにログインする方法は2つあります。

  • パスワード認証
  • 公開鍵認証

この二つです。

SSHの利用準備

SSHを利用するためには、リモートにSSHサーバ
ローカルにSSHクライアントというソフトウェアをインストールする必要があります
しかし、LinuxサーバやMac OSには標準でインストールされているのでインストールする必要はありません。

ターミナル
$ ssh [ ログインユーザー名 ]@[ IPアドレス ] # これでリモートサーバにログインできます。

SSHクライアント

リモートにインストールさせる

SSHサーバ

ローカルにインストールさせる

サーバに入れる人を制限する設定
サーバに入れる人を制限するためには「秘密鍵」と「公開鍵」という2つのファイルを使います。

ターミナル
$ ssh-keygen -t rsa # SSH通信で必要になる、公開鍵と秘密鍵の両方が生成されます。

公開鍵

公開鍵は、サーバへのSSHを始めるときに一緒に送ります。
そこで暗号が生成されます。
鍵穴というイメージといえばわかりやすいです。

秘密鍵

秘密鍵は、ローカル環境内に保存しておきます。
そこで公開鍵の暗号が解読されます。
そのまま鍵といえばわかりやすいです。

通信手順

通信を行う際は
1,サーバへのSSHを始めるときに一緒に送った公開鍵を元に暗号が生成(鍵穴を作成する)
2,ローカル環境ではサーバから送られてきた暗号を秘密鍵を基に解読します。(鍵を作って開ける)
このようにして、サーバーとローカル環境間の情報のやりとりが安全に行われます。

公開鍵でログイン

手順は三つ
①公開鍵と秘密鍵を生成(ローカル環境側)
②公開鍵をサーバ側に設置(ローカル環境側→サーバ側)
③公開鍵認証でログインできるか確認

①公開鍵と秘密鍵を生成

ターミナル(ローカル)
~ $ cd .ssh # .sshディレクトリへ移動
.ssh $ ssh-keygen -t rsa  # 公開鍵と秘密鍵を作成

上記のコマンドを入力後、以下のように表示され
秘密鍵の保存場所と秘密鍵に設定するパスワードを入力します。

ターミナル(ローカル)
# 秘密鍵を保存するときの名前は、デフォルト(id_rsa)のままで良いので何もせずにenterキーを押します。
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/hogehoge/.ssh/id_rsa): [秘密鍵の置き場所] 
# ここで.sshディレクトリに秘密鍵が置かれます。

# 秘密鍵に設定するパスワードを入力(忘れないよう覚えておきましょう)
Enter passphrase (empty for no passphrase): [パスワード] #パスワードを設定してください。
Enter same passphrase again: [パスワード] #もう一度同じパスワードをうってください。

ローカル環境の公開鍵と秘密鍵の保存場所はデフォルトで決まっています。
公開鍵は ~/.ssh/id_rsa.pub
秘密鍵は~/.ssh/id_rsaに保存されています。

以下のコマンドを入力して、出力結果に以下の2つが含まれていれば作成成功です。

ターミナル(ローカル)
$ ls
=> [鍵の名前]_key_rsa [鍵の名前]_key_rsa.pub

catコマンド

catコマンドは、catと入力した後に記述するファイルの中身を確認するコマンドです。

公開鍵と秘密鍵を作成できたか、catコマンドを使って公開鍵の中身を確認します。

ターミナル(ローカル)
# 公開鍵の中身を確認
$ cat [公開鍵]_key_rsa.pub

#秘密鍵の中身を確認
$ cat [秘密鍵]_key_rsa

コマンドを実行すると、複雑な文字列がターミナル上に表示されます。
これが、先ほど作成した公開鍵と秘密鍵の中身になります。

②公開鍵をサーバ側に設置

公開鍵をサーバ側に設置するため2つの処理を行います。

  • リモートサーバにローカル環境の公開鍵のファイル(id_rsa.pub)をコピー
  • ローカル環境の公開鍵のファイル(id_rsa.pub)の中身をリモートサーバの公開鍵のファイル(~/.ssh/authorized_keys)に追記

scpコマンド

scpコマンドとは、送信先のディレクトを指定してファイルを送ることができるコマンドです。

# .sshディレクトリにローカル環境の公開鍵のファイル(id_rsa.pub)をコピー
$ scp ~/.ssh/id_rsa.pub [ユーザー名]@ [IPアドレス]:~/.ssh

AWSの場合

AWSの場合は、あらかじめ秘密鍵(pem)でsshができるようになっているので以下のようにするのが一般的です。

$ ssh -i [ダウンロードした鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]

実際の手順

ローカル環境の公開鍵のファイル(id_rsa.pub)の中身を
リモートサーバの公開鍵のファイル(~/.ssh/authorized_keys)に追記

今までローカル環境では
公開鍵はid_rsa.pubに保存しましたが、リモートサーバでは公開鍵は ~/.ssh/authorized_keysに保存します。

ターミナル
# リモートサーバにログイン
$ ssh [ユーザー名]@ [IPアドレス]

# .sshディレクトリへ移動
$ cd ~/.ssh  

# リモートサーバの公開鍵のファイル(~/.ssh/authorized_keys)を作成
touch .ssh/authorized_keys

# 公開鍵の中身を追記
$ cat ~/id_rsa.pub >> authorized_keys

最後に.sshディレクトリとauthorized_keysファイルの権限を設定します。 .sshディレクトリには読み・書き・実行のすべての権限、authorized_keysファイルには読み・書きの権限を設定します。

# .sshディレクトリとauthorized_keysファイルの権限を設定
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys

公開鍵認証でログインできるか確認

作業が終わったので
公開鍵認証でログインできるか確認します。

# リモートサーバにログイン
$ ssh [ユーザー名]@ [IPアドレス]

コマンドを打った後、下記のような表示がされます。
①公開鍵と秘密鍵を生成の# 秘密鍵に設定するパスワードを入力のところで記述したパスワードを入力します。
その後[ユーザー名]@ [IPアドレス]% と表示されていればログイン成功です。

Enter passphrase for key '~/.ssh/id_rsa':  ←パスワードを入力 
[ユーザー名]@ [IPアドレス]%  ←SSHサーバにログイン成功
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DELL管理ツール(OMSA)のインストール方法・利用方法

はじめに

  • DELLのサーバを利用している方ならご存知かと思いますが、OMSA(OpenManage Server Administrator)のナレッジを整理します。

OMSAとは

  • DELLが提供している管理ツールOpenManage Server Administrator(通称:OMSA)のこと。
  • WebブラウザやCUIでHW状態確認が可能。

OMSAインストール手順

  • DELLのyum repositoryを設定。
# wget -q -O - http://linux.dell.com/repo/hardware/latest/bootstrap.cgi | sudo bash
  • OMSAのコンポーネントをyumでインストール。
# yum install -y srvadmin-all
  • OMSAを起動。
# /opt/dell/srvadmin/sbin/srvadmin-services.sh start

OMSAの利用

  • OMSAが起動した状態でWebブラウザから以下のURLへアクセスする。

    • https://<ホスト名 or IPアドレス>:1311/
  • 以下のログイン画面が出るので、ユーザとパスワードを入力する。

51526059-e5aef980-1e74-11e9-968a-a42836551bd4.png

  • ログインをすると、HWの状態やログを確認することが可能となる。
    • 2枚目のキャプチャはストレージの状態を確認したサンプル

51526066-e8115380-1e74-11e9-816a-aaef12f857a5.png
51526080-eb0c4400-1e74-11e9-8bbb-38a40b2c8bdf.png

CLIの使い方

  • OMSAをインストールすると、CLIでHWの状態確認を行うことが可能になる。
    • 詳細は別途、整理予定。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows10のWSLでLinuxを使う手順

Windows10のWSLでLinuxを使う手順

WSLを有効にする

Win+Rで「ファイル名を指定して実行」ダイアログを開く
controlと入力して<ENTER>

Clipboard01.jpg

「プログラムと機能」をクリックして、表示されたウィンドウから
「Windowsの機能の有効化または無効化」をクリック

Clipboard02.jpg

「Windows Subsystem for Linux」のチェックを入れてOK
再起動

Clipboard03.jpg

Linux(Ubuntu)をインストールする

スタートメニューからMicrosoft Storeを実行し「ubuntu」で検索する。
検索結果から「Ubuntu」をクリック、続いて「入手」をクリックでしばらく待てばインストールが完了する

その後、ユーザー名とパスワードを聞かれるのでそれぞれ入力して完了

Ubuntuの起動

スタートメニューの「ubuntu」アイコンをクリックで起動
またはプログラムを指定して実行で「ubuntu」を指定で起動

pxoryとaptの設定

proxyの設定
というか、proxy環境下の設定(ubuntu 14.04) - Qiitaを参考に設定

export https_proxy=ProxyのURL
export http_proxy=ProxyのURL

aptのproxy設定(ファイルは新規に作成する)

/etc/apt/apt.conf
Acquire::ftp::proxy "ftp://username:password@your.proxy.address:proxy.port/";
Acquire::http::proxy "http://username:password@your.proxy.address:proxy.port/";
Acquire::https::proxy "https://username:password@your.proxy.address:proxy.port/";

aptのupdate

$ sudo apt-get update

その他、aptの使い方
aptコマンドチートシート - Qiita

gccとかmakeとかの開発ツールインストール

sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev
sudo apt-get install libffi-dev

gitからdotfilesとかダウンロード

gitのSSL無視。必要な場合のみ。

$ git config --global http.sslVerify false

gitから設定ファイル等をクローンしてくる。必要な場合のみ。

$ git clone htts://github.com/<user_name>/<repository_name>.git
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

開発者なら知っておくべき 11 のコンソールコマンド

こちらの記事は、Indrek Lasn 氏により2019年 11月に公開された『 Here Are 11 Console Commands Every Developer Should Know
』の和訳です。
本記事は原著者から許可を得た上で記事を公開しています。

コマンドラインをうまく使えば、いくつかのありふれたタスクを自動化し、よりスムーズに処理を実行することが可能になり、日々の生産活動をより効率化できます。GUI上でクリック操作する代わりに、いくつかのコマンドを実行するだけでジョブを完了させることが可能です。

Unix shell はUnixライクなOS向けにコマンドラインユーザーインターフェースを提供する、コマンドラインインタプリター、またはshellです。shellはインタラクティブなコマンド言語かつスクリプト言語でもあり、OSがshellスクリプトを用いてシステムの実行を制御するために使用されます。

すべてのLinuxやMacベースのOSにはデフォルトでコマンドラインがインストールされており、一般的には「ターミナル」と呼称されます。コマンドライン(CLI)によってファイルの移動や名前の変更、データの並び替えやコンピュータ内の移動をより簡単に行えます。

では早速あなたのエンジニアライフをより楽にする “11” のコマンドを紹介します。

1. grep

$ grep "some string" file

grepコマンドは各ファイルの文字列を検索します。また、改行文字で区切られたパターンも検索し、パターンに一致する行をそれぞれ出力します。

1_ovG5it9EJTZ0JG3tdOgclA.png

grep でファイル内の React という文字列を検索する


-i オプションを使用すると、指定したファイル内の大文字と小文字を区別せずに文字列を検索できます。この場合「REACT」、「REact」、「react」などの文字列を検索します。
$ grep -i "REact" file

-c (count)オプションを使用すると、指定された文字列/パターンがファイル内で何回記載されているかがわかります。

$ grep -c "react" index.js

1_-KL9UvoB8RR4NKkUfHNBoQ.png

grep -c コマンドで react の 記載回数をカウント



これは私がインターネットで見つけた、grepコマンドに関する楽しくてためになるイラストです。

1_ZkpszLnLQFRFp_cVO_Ldmw.jpeg
Source: Wizard Zines

また、異なるコマンドの egrep および fgrep は、それぞれ grep -E および grep -F と同様のコマンドです。これらのバリアントは非推奨ですが、下位互換性のために提供されています。

grep では多くのことを行えます。--より深く理解するためにはこのドキュメントを読んでください。

2. ls

$ ls

ls コマンドはパス内のファイルとディレクトリを一覧表示します。パス名がファイルの場合、ls コマンドは要求されたオプションに従ってファイルに関する情報を表示します。

パス名がディレクトリの場合、ls コマンドはディレクトリ内のファイルとその中のサブディレクトリに関する情報を表示します。

1_JthCA8XeIN22yScYBJlRIw.png

ls でパス内のすべてのディレクトリとファイルを表示



フォルダが青色で表示されているのに対し、ファイルはグレーで表示されていることに気づいたかもしれません。これは、フォルダとファイルを区別するのに役立ちます。

3. pwd

$ pwd

1_E1zXuIQ6X0aaTtVC0wZ_nw.png

pwd で作業ディレクトリの絶対パスを表示



pwd コマンドは、現在の作業ディレクトリを出力するコマンドです。現在の作業ディレクトリの完全なシステムパスを標準で出力します。オプションで現在のディレクトリの完全な物理パスを表示できますが、デフォルトでは、pwd コマンドはシンボリックリンクを無視します。

4. cat

$ cat somefile.js

1_SL7g1NHsb7dKgwmoYBySkQ.png

cat でファイルの内容を表示



cat コマンドには、テキストファイルに関する3つの関連機能があります。
  • テキストファイルの内容を表示する
  • テキストファイルのコピーを結合する
  • 新しいテキストファイルを作成する

cat コマンドの最も一般的な使い方は、ファイルの内容を読み取ることであり、多くの場合この目的に最も便利なコマンドです。

以下の例では、cat の標準出力は、出力リダイレクト演算子( > で表されます)を使用してfile2にリダイレクトされます。

$ cat somefile > somefile2

1_NxLOMigqozU5EvxVdr1f7Q.png

cat を使ってファイルを作成する

5. echo

$ echo "some text"

Linux の echo コマンドは、引数として渡されたテキスト/文字列を表示するために使用されます。echo コマンドは主にシェルスクリプトやバッチファイル内で使われ、ステータス情報のテキストを画面やファイルに出力します。

1_1bMjVqwhueQP5hvyMMdDKA.png

6. touch

$ touch somefile

touch コマンドは空ファイルを作成するために使用されます。touch コマンドは、ユーザーがファイル作成時点ではデータを保存する必要がない場合に使用されます。
1_RIrUCSW4TT_cJrnGy9ighQ.png

touch で新しいファイルを作成



上の図ではtouch を使ってファイルを作成し、cat でファイルの内容を確認しています。新しく作成されたindex2.jsファイルは空なので、cat は何も返しません。

以下はcattouch の主な違いです:

  • cat — コンテンツを含むファイルを作成するために使用されます。
  • touch — コンテンツ無しまたは空ファイルの状態でファイルを作成します。touch コマンドで作成したファイルは空だということに注意してください。このコマンドは、ユーザーがファイル作成時点で保存するデータがない場合に便利です。

7. mkdir

$ mkdir some-directory

単語から推測できる通り、mkdir は現在のアクティブパスに新しい空のディレクトリを作成します。テキストエディターやGUI上でクリックする代わりに、このコマンドを使用して新しいフォルダーを作成します。
1_FsxDBW5HDWJn9kHsw0My7A.png

mkdir で新しいディレクトリを作成



注:前述のls コマンドでディレクトリ内をどのように覗くことができるか確認してみてください。

7.1 rm

$ rm someFile

rm はremoveの略で、まさにそのまま言葉通りのことをします。つまり、ファイルを取り除く、別の言葉で言えば、削除します。

1_damLEKdyWY7aBPILFELVNg.png

rm コマンドでファイルを削除



デフォルトでは、rm コマンドはディレクトリを削除しません。ディレクトリを削除するには、(rm) -rf オプションを渡す必要があります。
$ rm -rf some-directory

1_gXTLAllsEVTdWHCcDw83WQ.png

rm -rf でディレクトリを削除(ディレクトリ削除のためのオプションを付与)



注:このコマンドにより、ディレクトリにコンテンツが含まれているかどうかに関係なくディレクトリが無条件に削除されます。

7.2 rmdir

$ rmdir some-directory

rmdir コマンドはディレクトリの内部にコンテンツがない場合にディレクトリを削除します。

1_aUJ0VbrVb_cTUf0okMxmWA.png

rmdir でからのディレクトリを削除

8. tail

$ tail somefile

tail コマンドはファイルの最後の部分(テール)を読み取り出力します。
1_Xvo2zdyDZqj4QhTHF0TLTg.png

デフォルト(10)の代わりに最後のnum 行を出力



tail コマンドは、クラッシュレポートや直近の履歴ログを調べるときに便利です。ファイルログを確認するときに有用となる例を以下に記載します。
# tail /var/log/messages
Mar 20 12:42:22 hameda1d1c dhclient[4334]: DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0x280436dd)
Mar 20 12:42:24 hameda1d1c avahi-daemon[2027]: Registering new address record for fe80::4639:c4ff:fe53:4908 on eth0.*.
Mar 20 12:42:28 hameda1d1c dhclient[4334]: DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0x280436dd)
Mar 20 12:42:28 hameda1d1c dhclient[4334]: DHCPACK from 10.76.198.1 (xid=0x280436dd)
Mar 20 12:42:30 hameda1d1c avahi-daemon[2027]: Joining mDNS multicast group on interface eth0.IPv4 with address 10.76.199.87.
Mar 20 12:42:30 hameda1d1c avahi-daemon[2027]: New relevant interface eth0.IPv4 for mDNS.
Mar 20 12:42:30 hameda1d1c avahi-daemon[2027]: Registering new address record for 10.76.199.87 on eth0.IPv4.
Mar 20 12:42:30 hameda1d1c NET[4385]: /sbin/dhclient-script : updated /etc/resolv.conf
Mar 20 12:42:30 hameda1d1c dhclient[4334]: bound to 10.76.199.87 -- renewal in 74685 seconds.
Mar 20 12:45:39 hameda1d1c kernel: usb 3-7: USB disconnect, device number 2

9. wget

$ wget someurl

wget (GNU Wget)は 最も広く使用されているインターネットプロトコルであるHTTP、HTTPS、FTP、およびFTPSを使用してファイルを取得するための、フリーソフトウェアパッケージです。ノンインタラクティブなコマンドラインツールであるため、スクリプト、CRONジョブ、X-Windowsサポートのないターミナルなどから簡単に呼び出すことができます。

1_nbzEhCeVUxT2-Px0oQbszQ.png

wget でウェブページの情報を取得



wget (GNU Wget)には、大きなファイルの取得やWebサイト、FTPサイト全体のミラーリングを容易にする以下のような多くの機能があります。
  • RESTとRANGEを使用して、中断したダウンロードを再開できます
  • ファイル名にワイルドカードを使用して、ディレクトリを再帰的にミラーリングできます
  • NLSベースの様々な言語向けメッセージファイル
  • オプションでダウンロードされたドキュメントの絶対リンクを相対に変換し、ダウンロードされたドキュメントがローカルで相互にリンクできるようにします
  • ほとんどのUNIXライクなオペレーティングシステムおよびMicrosoft Windowsで実行可能
  • HTTPプロキシをサポート
  • HTTP Cookieをサポート
  • 持続的なHTTP接続をサポート
  • コンソール無接続 / バックグラウンド でのダウンロードをサポート
  • ローカルファイルのタイムスタンプを使用して、ミラーリング時にドキュメントを再ダウンロードする必要があるかどうかを判断
  • GNU WgetはGNU General Public Licenseのもとで配布されています。

詳細については、公式のGNUドキュメントを参照してください。

10. find

$ find path -name filename

find コマンドによりファイルまたはディレクトリをすばやく検索できます。数百以上のファイルや複数のディレクトリを持つ、大きなプロジェクトで作業する場合に便利です。
1_j291SZcYXSaPtdvqipX6sg.png

find でディレクトリ内のindex.jsという名前のファイルすべてを見つける

特定の種類のファイルを検索する

find コマンドを使用すると、ディレクトリ(およびそのサブディレクトリ)内で同じタイプのファイルを検索することもできます。例えば以下のコマンドは現在の作業ディレクトリ内のすべての .js ファイルを検索します。

$ find . -name "*.js"

1__i8_TEIElXAAyXy-F1JQmA.png

componentsディレクトリですべての .js ファイルを見つける

11. mv

$ mv somefile /to/some/other/path

mv コマンドは、ファイルまたはディレクトリをある場所から別の場所に移動します。このmv コマンドは、単一ファイル、複数ファイル、およびディレクトリの移動をサポートしています。

1_TdqoyPUFrdBvI2Ws7cfyfQ.png

some-directory を components からutils に移動する

最後に..

ここまで読んでいただきありがとうございます。何か得るものがあったなら幸いです。もっと便利なコマンドを知っている場合は是非共有していただき、一緒に成長していきましょう。

-貪欲であれ。好奇心旺盛であれ。-

翻訳協力

 
Original Author: Indrek Lasn
Thank you for letting us share your knowledge!

この記事は以下の方々のご協力により公開する事が出来ました。
改めて感謝致します。
選定担当: Yumika Tomita
翻訳担当: @upaldus
監査担当: @nyorochan
公開担当: @miyonori0812

ご意見・ご感想をお待ちしております

今回の記事は、いかがだったでしょうか?
・こうしたら良かった、もっとこうして欲しい、こうした方が良いのではないか
・こういったところが良かった
などなど、率直なご意見を募集しております。
いただいたお声は、今後の記事の質向上に役立たせていただきますので、お気軽にコメント欄にてご投稿ください。Twitterでもご意見を受け付けております。
みなさまのメッセージをお待ちしております。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

sudoの「大いなる力」の元ネタを探して

「大いなる力には大いなる責任が伴うこと」の由来は?

君はsudoコマンドのlectureを見たことがあるか?

UNIX系OSという世界の中で、あらゆることが可能なrootユーザーのように振舞える魔法のことば、
sudo

これを唱えたとき、MPが足りない 権限が足りなかったりすると
以下のような警告が表示されます。

あなたはシステム管理者から通常の講習を受けたはずです。
これは通常、以下の3点に要約されます:

    #1) 他人のプライバシーを尊重すること。
    #2) タイプする前に考えること。
    #3) 大いなる力には大いなる責任が伴うこと。

[sudo] [貴方のユーザ名] のパスワード:

大いなる力...

1も2も、まぁ、わかります。
プライバシーは大事だし、
本当にsudoで実行して良いコマンドなのか、一呼吸おいて考えることが出来ます。

気になったのは、3です。(アメコミ好きなそこの貴方、気になりますよね)

「大いなる力には大いなる責任が伴うこと。」

そう、スパイダーマンにも出てくる言葉です。

英語だと、
「With great power comes great responsibility.」
リピートアフターミー。

初出は、Amazing Fantasy #15 (August 1962)のキャプションから、
ということなので、1962年からあるんですね。
※wikipedia調べ(以下、特に記載ない情報はwikipediaによります)
※ちなみに筆者は原作を知りません。ごめんなさい。

sudoとスパイダーマンどっちが早かった?

では、Linuxのsudoの警告とスパイダーマン、どっちが早いでしょうか?

sudoの歴史は、下記のsudoのプロジェクトサイトに記載があります。

https://www.sudo.ws/sudo/history.html
A Brief History of Sudo
Sudo was first conceived and implemented by Bob Coggeshall and Cliff Spencer around 1980 at the Department of Computer Science at SUNY/Buffalo.

ふむ、作られたのは1980年のようですね。

当初から「大いなる力には...」と実装していたわけではないと思いますが、

スパイダーマン(1962年) < sudo(1980年)

この時点で、スパイダーマンが元ネタだろう、という推測が成立しました。

sudoにこのセリフが導入されたタイミングや「本当にネタ元なのか?」を調べるならば、
おそらく上記のsudoプロジェクトのコミットログやメーリングリストの履歴を読み込むのがベストでしょう。

が、追っていると年越してしまいそうなので、やめておきます。
(筆者が検索した限りでは、特定できませんでした。ダンジョンに繰り出す勇者を待ちます)

スパイダーマンのこのセリフの由来は、少しネットの世界を検索してみると、
フランス語のノブレス・オブリージュ「高貴さは(義務を)強制する」や
聖書に原典を求める説もあるようです。

原典に当たることの大切さ

rootユーザーは、絶大な権限を持ちますので、
パスワードを入力させるというステップを設けることで、ユーザーに自覚を持たせ、
一時的にその権限を付与する、というsudoの設計思想には普遍性を感じられ、感服いたします。

今回、ひょんなことから、sudoのプロジェクトのWebサイトまでたどり着きました。
コマンドのヘルプにはいつもお世話になっておりますが、
各プロジェクトの原典となるサイトを訪れることは、なかなかやりません。

実際、筆者もsudoの設計思想を考えたことが無く、良い機会になりました。

この記事を読んでくださった皆様も、ぜひ普段お使いのコマンドやツールの作者の意図や意志、
その歴史を、原典まで遡って、追いかけてみてはいかがでしょうか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UNIX系クイックコマンドリファレンス

UNIX系クイックコマンドリファレンス

書いておいてすみませんが、私が作ったかなり古い資料(2012)でかつ調査しきれず抜けている箇所も散見されますが、ご容赦ください。

文字コード

デフォルト文字コード AIX HP-UX Solaris Linux(Debian系)Ubuntu8.04LTS Linux(Red Hat系) FreeBSD
デフォルト文字コード Shift_JIS Shift_JIS EUC-JP EUC-JP??? Ubuntu8.04は、UTF8 UTF8(RHEL4以降) EUC-JP
言語 Ja-JP ja_JP.SJIS ja_JP.eucJP ja_JP.UTF-8 ja_JP.UTF-8 ja_JP.eucJP

  

パッケージ管理

パッケージ AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
パッケージのインストール installp -a swinstall pkgadd dpkg -i [パッケージ] apt-get install [パッケージ] rpm -i pkg_add
パッケージの削除 installp -u swremove pkgrm パッケージを削除する(設定ファイルは残す) dpkg -r [パッケージ] パッケージを完全に削除する(設定ファイルも削除) dpkg --purge [パッケージ] rpm -e pkg_delete
パッケージの一覧 lslpp -L all swlist pkginfo dpkg -l rpm -qa pkg_info -a
パッケージのファイル表示 lslpp -f fileset swlist -l file pkgchk -l dpkg -L [パッケージ] rpm -ql pkg_info -L
ファイルからのパッケージ検索 lslpp -w path swlist -l file \ grep pkgchk -l -p dpkg -S [ファイル名] rpm -qf
パッケージ情報のディレクトリ /usr/lpp /var/adm/sw /var/sadm /var/lib/rpm /var/db/pkg

デバイス管理

デバイス AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
Install devices for attached peripherals cfgmgr -v insf -e drvconfig devlinks disks tapes ports /dev/MAKEDEV /dev/MAKEDEV
デバイス削除 rmdev -l rmsf rem_drv
デバイスドライバー lscfg lsdev kcmodule -v prtconf -D lsmod
CPU lsdev -Cc processor ioscan -fnC processor psrinfo -v cat /proc/cpuinfo sysctl hw.model
List Terminal lsdev -Cc tty ioscan -fnC tty pmadm -l
ダイアグ(機器情報) diag stm /usr/platform/uname -m/sbin/prtdiag ok test-all /opt/SUNWvts/bin/sunvts lspci lspci pnpdump pciconf -l
デバイス診断情報 lscfg ioscan
ファームウェア lscfg-vl machinfo
CPUクロック速度 prtconf -s machinfo
物理メモリサイズ prtconf -m machinfo
CPUタイプ prtconf -c machinfo

ネットワーク

ネットワーク AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
ネットワーク設定 lsattr -E -l inet0 /etc/rc.config.d/netconf /etc/hostname /etc/nodename /etc/netmasks /etc/inet/* /etc/defaultrouter /etc/network/interfaces /etc/sysconfig/network-script/* /usr/sbin/netconfig /etc/rc.conf
hostsファイル /etc/hosts /etc/hosts /etc/inet/hosts /etc/hosts /etc/hosts /etc/hosts /etc/hosts
ネームサービスの設定 /etc/netsvc.conf /etc/nsswitch.conf /etc/nsswitch.conf /etc/resolv.conf /etc/nsswitch.conf /etc/resolv.conf /etc/nsswitch.conf /etc/resolv.conf /etc/host.conf
ネットワークデバイスの設定 ifconfig -a lanscan -v ifconfig -a ifconfig -a iwconfig -a(無線LAN) ifconfig -a ifconfig -a
port開放 /etc/services /etc/services /etc/services /etc/services /etc/services /etc/services
NFS exportsファイル /etc/exports /etc/exports /etc/dfs/dfstab /etc/exports /etc/exports
Secondary IP Address ifconfig en0 alias IP ifconfig lan0:1 IP ifconfig hme0:1 IP up modprobe ip_alias ifconfig eth0:1 IP modprobe ip_alias ifconfig eth0:1 IP ifconfig xl0 alias IP
リモートシェル remsh rsh remsh rsh rsh rsh rsh

ディスク

ディスク AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
ファイルシステムテーブル /etc/filesystems /etc/fstab /etc/vfstab /etc/fstab /etc/fstab /etc/fstab
ディスク利用状況 df -k bdf df -k df -k df -k df -k
ディスク情報 bootinfo -s hdisk# diskinfo /dev/rdsk/c#d#t# format -d c#d#t# format>current format>inquiry cat /proc/ide/ide0/had/model cat /proc/ide/ide0/had/model fdisk -v ad0
デバイスリスト lsdev -C /sbin/ioscan sysdef cat /proc/devices cat /proc/devices -
ディスクラベル lspv -l hdisk# pvdisplay -v prtvtoc fdisk -l fdisk -l disklabel
ジャーナルファイルシステム jfs jfs2 vxfs vxfs ext3 ext3 reiserfs -
fs表示 lsfs
fs作成 /usr/sbin/crfs -v jfs2 -d lv_name newfs mkfs mke2fs
fsリスト /usr/sbin/lsfs
fs変更 chfs resize2fs
lvol表示 lslv lvdisplay -C
lvol作成 mklv lvcreate
lvolリスト /usr/sbin/lsvg -o\ /usr/sbin/lsvg -i -l lvscan lvs
lvol変更 /usr/sbin/extendlv lvchange lvextend
VG表示 lsvg -l rootvg vgdisplay -v vg00 vxprint -l -g rootdg vgdisplay -v ※lvm2要 vgdisplay -v vgs -
VG作成 mkvg vgcreate vxdg init vgcreate ※lvm2要 vgcreate
VGリスト lsvg vgscan vgscan vgscan
VG変更 chlv lvchange vxedit set lvchange ※lvm2要 lvchange
PV作成 mkdev -c disk -l hdisk# pvcreate vxdiskadd pvcreate ※lvm2要 pvcreate -
PVリスト lspv pvdisplay vxprint -dl pvdisplay ※lvm2要 pvdisplay pvs vinum ld
PV変更 chpv pvchange pvchange ※lvm2要 pvchange -
スワップサイズの状態 lsps -a swapinfo -a swap -l free free swapinfo
スワップの有効化 swapon -a swapon -a swap -a swapon -a swapon -a
スワップのデバイス /dev/hd6 /dev/vg00/lvol2 /dev/vx/dsk/swapvol /dev/sda2 /dev/ad0s1b

外部メディア

外部メディア AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
リワインド・テープ・デバイス /dev/rmt0 /dev/rmt/0mn /dev/rmt/0 /dev/rst0 /dev/rwt0d
フロッピードライブ /dev/rfd0 - /dev/diskette /dev/fd /dev/fd0 /dev/fd0
CD-ROMデバイス /dev/cd0 /dev/dsk/c#d#t0 /dev/dsk/c#d#t0p0 /dev/cdrom /dev/cdrom(/dev/hdcなど) /dev/acd0
CD-ROMファイルシステム cdrfs cdfs hsfs iso9660 cd9660

性能

性能 AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
プロセスモニタ top monitor top glance prstat top nice -10 top -d 2 top ※sysstat要 top top
システム監視ツール sar sar sar sar ※sysstat要 sar {sysstat} sa
物理メモリの表示 bootinfo -r grep Phys /var/adm/syslog/syslog.log* prtconf \ grep memory free free
仮想メモリの状態 vmstat vmstat vmstat vmstat ※sysstat要 vmstat vmstat
I/Oの状態 iostat iostat iostat iostat ※sysstat要 iostat iostat

ディスク構成

ディスク構成 AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
Partition logical extents sub disk logical extents sub disk
Volume logical volume Volume logical volume Volume
Plex Plex
Volume group volume group disk group volume group

カーネル,OS

カーネル,OS AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
カーネルファイル /usr/lib/boot/unix_up /stand/vmunix /kernel/genunix /boot/vmlinuz /boot/vmlinuz /boot/kernel
カーネルパラメータ lsattr -E -l sys0 sysdef kmtune⇒kctune kmsystem sysdef -i sysctl -a ulimit -a sysctl -a sysctl -a
モジュールの表示 genkex kmadmin -s modinfo lsmod lsmod kldstat
モジュールのアンロード - kmadmin -U modunload modprobe rmmod kldunload
モジュールのロード kmadmin -L modload update-modules insmod kldload
モジュール設定ファイル /etc/modules
システムコールのトレース syscalls tusc truss strace strace truss ktrace
マシンタイプ uname -m bootinfo -m prtconf model uname -m uname -imp uname -m uname -m uname -m
OSバージョン oslevel uname -r uname -r uname -r uname -r cat /etc/lsb-release uname -r cat /etc/redhat-release uname -r
使用中のカーネル prtconf -k
コアダンプファイル /var/adm/ras /var/adm/crash /var/crash/uname -n / - -
タイムゾーン /etc/environment /etc/profile /etc/TIMEZONE /etc/TIMEZONE /etc/default/init ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime /etc/sysconfig/clock /etc/localtime
NTP設定 /etc/ntp.conf startsrc -s xntpd /etc/rc.config.d/netdaemons /sbin/init.d/xntpd /etc/inet/ntp.conf /etc/init.d/xntpd /etc/ntp.conf ※ntp要 /etc/ntp.conf /etc/rc.d/init.d/xntpd /etc/rc.conf {xntpd_enable="YES"} /etc/rc.network
スタートアップスクリプト /etc/rc /sbin/rc /etc/init.d /etc/rc.d/rc /etc/rc

ランレベル

ランレベル AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
現在のランレベル who -r who -r who -r runlevel -
デフォルト・ランレベル init2 init2 init5
init 0 将来オペレーティング・システムが使用するために予約。 システム停止。/sbin/rc0.d 内にあるあらゆる停止(K)および起動(S)スクリプトが実行される。 パワー・ダウン状態。この状態の時にだけ電源を切ることができる。 停止 システム停止
init 1 将来オペレーティング・システムが使用するために予約。 シングルユーザモードで、ファイルシステムがマウントされた状態。 システム管理状態(シングル・ユーザー)。 / と /usr ファイル・システムだけがマウントされている。他のユーザーは、ログイン出来ない。 シングルユーザーモード シングルユーザーモード
init 2 マルチユーザモード NFSなしのマルチユーザモード。 通常の状態で、複数のユーザーがファイルシステムにアクセス出来る。NFSサーバー(syslog、RFSも)が動いていない。 マルチユーザーモード ローカルマルチユーザモード(NFSなどはなし)
init 3 ユーザが定義。 HP CDEマルチユーザモード。NFSが使用可能。 マルチ・ユーザー状態(リソースがエキスポートされている)。通常の動作状態。 init2に同じ フルマルチユーザモード(テキストコンソール)
init 4 ユーザが定義。 HP VUEマルチユーザモード。HP-UX10.10以前の環境。 別のマルチ・ユーザー状態。現在使われていない init2に同じ 未使用
init 5 ユーザが定義。 未定義。 ソフトウェア・リブート状態。デフォールトのブート・デバイス以外のデバイスを指定する。 インターラクティブなリブート状態。 reboot -a と同じ。 init2に同じ フルマルチユーザモード(グラフィカル環境)
init 6 ユーザが定義。 未定義。 リブート。システムを行ったんレベル0に落し、マルチ・ユーザーで立ち上げる。 再起動 システム再起動
init s コマンドを保守モードに入るよう指示する。システムが別の実行レベルから保守モードに入ると、システム・コンソールだけが端末として使用される。 シングルユーザモード。/sbin/rc0.d 内にあるあらゆる停止(K)および起動(S)スクリプトが実行される。 ※ワンポイント /sbin/rcn.d 内のファイルは、通常 /sbin/init.d 以下のファイルにシンボリックリンクしている。 シングル・ユーザー状態。全てのファイルシステムがマウントされている。 シングルユーザーモード
init S コマンドを保守モードに入るよう指示する。システムが別の実行レベルから保守モードに入ると、システム・コンソールだけが端末として使用される。 S(大文字のS)だと、システムコンソールの機能は、このコマンドを実行したログイン中の端末に切り替わり root で自動ログインした仮想システムコンソールとなる。 シングル・ユーザー状態。全てのファイルシステムがマウントされている。
シングルユーザモードへの切替 shutdown -Fm ISL> hpux -is boot /stand/vmunix HPUX> boot -is vmunix ?shutdown -r shudown -y -g0 -iS 電源を入れ、Boot:という画面が出たらすぐに、-sと入力します。 Boot: -s

ランレベルと rcスクリプト

ランレベルと rcスクリプト AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
システムの動作状態規定 /etc/inittab /etc/inittab /etc/inittab
スクリプト格納フォルダ /etc/init.d/ /sbin/init.d /sbin/init.d /etc/init.d/ /etc/rc.d/init.d/
ランレベルS /sbin/rcS /sbin/rcS, /etc/rcS.d/* /etc/rcS.d/
ランレベル0 /etc/rc.d/rc0.d /sbin/rc0 /sbin/rc0, /etc/rc0.d/* /etc/rc0.d/ /etc/rc.d/rc0.d/
ランレベル1 /etc/rc.d/rc1.d /sbin/rc1 /sbin/rc1, /etc/rc1.d/* /etc/rc1.d/ /etc/rc.d/rc1.d/
ランレベル2 /etc/rc.d/rc2.d /sbin/rc2 /sbin/rc2, /etc/rc2.d/* /etc/rc2.d/ /etc/rc.d/rc2.d/
ランレベル3 /etc/rc.d/rc3.d /sbin/rc3 /sbin/rc3, /etc/rc3.d/* /etc/rc3.d/ /etc/rc.d/rc3.d/
その他 /etc/rc.tcpip inittabからTCP/IP daemonsに関連するデーモンを起動する。 /etc/init.d/以下にシェルスクリプトを配置 update-rc.d <スクリプト名> default をrootで実行 /etc/rc*.d/以下にシンボリックリンクが自動生成される
デーモン起動スクリプト登録コマンド chkconfig

一般操作

一般操作 AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
パスワードファイル /etc/passwd /etc/security/passwd /etc/passwd /tcb/files/auth/r/root /etc/passwd /etc/shadow /etc/passwd /etc/shadow /etc/passwd /etc/shadow /etc/passwd /etc/master.passwd
rootパスワードリカバリ boot from CD/Tape Installation/Maintenance Start Limited Shell getrootfs hdisk0 vi /etc/security/passwd >boot Interact with IPL ? Y ISL>hpux -iS passwd root boot cdrom -s mkdir /tmp/a mount /dev/c0t0d0s0 /tmp/a vi /tmp/a/etc/shadow {lilo} control-x linux S passwd root {grub} c kernel vmlinuz-2.4.9-13 single ro root=/dev/hda8 initrd /initrd-2.4.9-13.img boot passwd root ok boot -s passwd root
ユーザの作成 mkuser useradd useradd adduser useradd adduser
ユーザの削除 rmuser userdel userdel deluser userdel rmuser
ユーザリスト lsuser -f ALL logins logins - - -
グループの作成 mkgroup groupadd
グループの削除 rmgroup groupdel
グループファイル /etc/group /etc/security/group /etc/group /etc/logingroup /etc/group /etc/group /etc/group /etc/group
ホスト独自ID hostid uname -i hostid hostid hostid -
設定ツール smit sam admintool debian : dpkg-reconfigure -a ubuntu : dpkg-reconfigure -a linuxconf fedora : setup vine : setup
X Window System設定ツール fedoa : Xconfigurator debian : dpkg-reconfigure xserver-xorg ubuntu : dpkg-reconfigure xserver-xorg turbo : turboxcfg
リモートログインの許可 /etc/security/user {rlogin=true} /etc/securetty {console} /etc/default/login {CONSOLE=/dev/console} /etc/securetty {ttyp1} /etc/securetty {ttyp1} /etc/ttys {secure}

シスログ

シスログ AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
シスログ /var/adm/ras/syslog.out ※syslog.confの設定をしないと出力なし errptにてOSのログ参照。 /var/adm/syslog/syslog.log /var/adm/messeges /var/log/messages /var/log/syslog /var/log/messages /var/log/messages
システム・ログ・デーモン・プロセス /usr/sbin/syslogd -N /etc/syslogd /sbin/syslogd /sbin/syslogd
シスログ設定ファイル /etc/syslog.conf /etc/syslog.conf /etc/syslog.conf /etc/sysconfig/syslog
syslogdの起動 startsrc -s syslogd /etc/init.d/syslog start /etc/init.d/sysklogd start /etc/rc.d/syslogd start service syslog start
syslogdの停止 stopsrc -s syslogd /etc/init.d/syslog stop /etc/init.d/sysklogd stop /etc/rc.d/syslogd stop service syslog stop
syslogdの稼働確認 lssrc -g ras ps -ef \ grep syslogd
syslogdの再起動 refresh -s syslogd kill -HUP syslogd PID /etc/init.d/sysklogd restart /etc/rc.d/init/syslog restart

OS起動・停止

OS起動・停止 AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
OS起動 boot
OS停止 shutdown -h now shutdown -F /usr/sbin/shutdown -h now /usr/sbin/reboot -h shutdown -i0 -g0 -y0 /sbin/shutdown -h /sbin/halt /sbin/shutdown -h /sbin/halt
OS再起動 shutdown -r now shutdown -Fr /usr/sbin/shutdown -r now /usr/sbin/reboot now shutdown -i6 -g0 -y0 /sbin/shutdown -r /sbin/reboot /sbin/shutdown -r /sbin/reboot

ファイルシステム

ファイルシステム AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
Rootファイルシステム / {/dev/hd4} / {/dev/vg00/lvol1} / {/dev/vx/dsk/rootvol} / {/dev/hda1} / {/dev/sda1} / {/dev/ad0s1a}
Homeディレクトリ /home {/dev/hd1} /home {/dev/vg00/lvol4} /export/home {/dev/vx/dsk/home} /home /home
tmpディレクトリ /tmp {/dev/hd3} /tmp {/dev/vg00/lvol6} /tmp {/dev/vx/dsk/swapvol} /tmp /tmp
usrディレクトリ /usr {/dev/hd2} /usr {/dev/vg00/lvol7} /usr /usr /usr /usr {/dev/ad0s1f}
varディレクトリ /var {/dev/hd9var} /var {/dev/vg00/lvol8} /var /var /var /var {/dev/ad0s1e}

セキュリティ

セキュリティ AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
ログイン成功履歴 last last last last
ログイン失敗履歴 last -f /etc/security/failedlogin lastb

パワードメイン

パワードメイン AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
パーティション技術 マイクロ・パーティショニング Virtual Server Environment Solaris Container
ハードウェアパーティション PPAR nPars(nPartitions) DSD(Dynamic System Domains)
パーティションの最小単位 システムボード セル・ボード システム・ボード
動作中の構成変更
パーティション間の隔離性 △ (拡張ボード共有時は隔離されない)
バックプレーンの隔離性 ×
ソフトウェアパーティション LPAR vPars LDOM
システムマネージャ SMS
システムコントローラ HMC MP SC
動的システムドメイン Dynamic Reconfiguration(DR)

ソフトウェアRAID

ソフトウェアRAID AIX HP-UX Solaris Linux(Debian系) Linux(Red Hat系) FreeBSD
ミラーディスク作成 mirrorvg -s rootvg hdisk1 (hdisk0にhdisk1を追加する) lvextend -m 1 /dev/vg01/lvol1 metainit volume-name -m submirror-name mdadm -C /dev/md0 -ayes -l raid1 -n 2 /dev/hdb1 /dev/hdb2
ミラーの同期 sysncvg -v rootvg
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【読解入門】Linuxカーネル (スケジューラと割込みハンドラの関係)

FUJITSU Advent Calendar 2019 13日目の記事です。

今回は、番外編としてLinuxカーネルにおけるスケジューラと割込みハンドラの関係を記事にします。2.6系の頃のカーネルと現在のカーネルでは割込みハンドラの扱いが大きく変化したため、この経緯なども踏まえて説明できればと思います。

・Linuxカーネルのコードは5.4を対象としています。
・アーキテクチャ依存の処理はArm(32bit)アーキテクチャで説明します。

割込みとは

初めに用語の定義から入ります。
割込みとは外部デバイスからイベントを通知する為の仕組みです。例えば、キーボードのキーを押下すると、キーボード デバイスからキーが押下されたことをCPUへ通知されることを割込みと言います。
割込みと似たような仕組みで例外があります。
例外は、プログラム実行時にメモリ アクセス違反や未定義命令などを実行した時に、イベントとして通知される仕組みです。
両者を区別する観点は幾つかあります。
一例としては、ソフトウェアの実行という観点で見ると、
・ソフトウェアの実行に同期して発生するイベントが例外
・ソフトウェアの実行と非同期で発生するイベントが割込み
と区別する事ができます。
また、イベントを発生させるハードウェアという観点で見ると
・CPU内部で発生するイベントが例外
・それ以外のデバイスから通知されるイベントは割込み
と捉えることもできます。

CPUが割込みを受けると、(ハードウェアで自動的に)ベクタ テーブルのIRQエントリのアドレスに制御が移ります。Arm(32bit)を例としてベクタ テーブルを説明します。ベクタ テーブルは下記のように定義されており、割込みの場合はオフセット0x18に制御が移ります。
このベクタ テーブルのアドレスは、0x00000000(ローベクタ)、または0xFFFF0000(ハイベクタ)のいずれかに配置されます。

ベクタ オフセット 要因
0x00 リセット
0x04 未定義命令
0x08 スーパーバイザー コール
0x0C プリフェッチ アボート
0x10 データ アボート
0x14 予約
0x18 IRQ
0x1C FIQ

ベクタ オフセット0x18に制御が移った後はソフトウェアで割込み発生時に実行していたコンテキストのレジスタ群を退避し、割込みハンドラを実行した後に、退避したレジスタ群を復元します。その後、元のコンテキストの実行を再開します。

割込みハンドラ

割込みハンドラは対応する割込みを受けた時に実行する処理のことを指します。
基本的に割込みハンドラはリアルタイム応答性能が求められるため、それまで実行していた処理に割り込んで実行する必要があります。
Linuxでは、処理の緊急性に応じて「ハードウェア割込みハンドラ」と「ソフトウェア割込みハンドラ」の2種類の割込みハンドラの仕組みが用意されています。

ハードウェア割込みハンドラ

緊急性の高い必要最低限の処理を実装します。
キーボードのキーを押下した場合の割込みを例で考えてみましょう。
割込み概要.jpg

ハードウェア割込みハンドラはキーボード デバイスの割込みを刈り取った後、押下されたキー情報を取得して、上位レイヤに通知して終了します。
押下されたキーに対するアクション(画面に表示する処理など)はハードウェア割込みハンドラでは行いません。
私なりの基本的な考え方は、至ってシンプルです。
割込みを上げたハードウェアにアクセスする処理はハードウェア割込みハンドラで、それ以外の処理はソフトウェア割込みハンドラで、を基準に考えています。

ソフトウェア割込みハンドラ

Linuxを扱う書籍、Webでは様々な呼び方がされています。ソフトウェア割込み、SoftIRQ、割込みの遅延処理など。
本記事ではこのソフトウェア割込みハンドラについてそれほど触れる予定もないので、この機能については別途記事を書きたいと思います。
割込み処理のうち、緊急度がそれほど高くなく、遅れて実行される処理と思っていただければ良いと思います。

従来の割込みハンドラの仕組み

以降はハードウェア割込みハンドラを「割込みハンドラ」と記述します。

割込みハンドラが使用するスタック

Linuxの割込みハンドラは、自身を実行する為のスタックを持ちません(少なくともx86、Arm(32bit)、Powerアーキテクチャにおいては)。下図の通り、割込みが発生した時点に実行していたプロセスのカーネルスタックを使用します。

割込みスタック.jpg

この図だけではイメージが湧かないと思いますので、実際の割込みハンドラ実行時のスタックの中を確認してみましょう。
今回はArmv7アーキテクチャのCPUを搭載したボード向けのLAN割込みハンドラの先頭にBUG( )を挿入しました。その時の出力情報を以下に示します。

まず初めに、1行目と35行目のコールトレースの情報から割り込ハンドラtest_interrupt( )を実行中にBUG( )を呼び出して、本メッセージが出力されていることが判ります。
次に6行目の"ti: c0af2000"からthread_info構造体の先頭アドレスが判ります。thread_info構造体とカーネルスタック領域は上図の関係にあるため、カーネルスタックが8KBの場合、このアドレスに0x2000を加算した0xc0af3FFFがスタックの底のアドレスになります。余談ですが、カーネルスタックのアドレスに対して0x1FFFをマスクすることで、そのプロセスのthread_info構造体のアドレスを算出できます。
次に注目して貰いたい箇所は4行目です。
実行しているプロセス情報が出力されており、PID 0のCPU 0用swapperプロセス実行時にBUG( )が呼ばれたことを意味しています。swapperプロセスは、システムがアイドル状態の時に実行されるIDLEクラスのプロセスです。
18 - 34行目はスタック領域の内容を表示しています。左端の4桁の数字は、スタックアドレスの下位16bitを表しています。
35 - 49行目のスタックトレースを見ると、47 - 49行目はswapperプロセスのコールトレースが表示されています。一方で、35 - 46行目は割込み発生後のコールトレースが表示されています。

これらのことから、割込みハンドラtest_interrupt( )までの一連の割込み処理はswapperプロセスのスタックを用いて動作していることが判ります。

 1 kernel BUG at drivers/net/ethernet/test.c:3639!
 2 Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM
 3 Modules linked in:
 4 CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.14.139 #8
 5 Hardware name: Test Board
 6 task: c0af97b0 ti: c0af2000 task.ti: c0af2000
 7 PC is at test_interrupt+0x14/0x18
 8 LR is at handle_irq_event_percpu+0x9c/0x30c
 9 pc : [<c04c8684>]    lr : [<c007d844>]    psr: 60010193
10 sp : c0af3df8  ip : c0af3e08  fp : c0af3e04
11 r10: c075dd90  r9 : c0af2000  r8 : 0000002b
12 r7 : 00000000  r6 : ed877f40  r5 : ee19e9b0  r4 : ed877f40
13 r3 : c04c8670  r2 : c0b89cc8  r1 : ed888000  r0 : 0000002b
14 Flags: nZCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
15 Control: 10c5387d  Table: 6db8804a  DAC: 00000015
16 Process swapper/0 (pid: 0, stack limit = 0xc0af2210)
17 Stack: (0xc0af3df8 to 0xc0af4000)
18 3de0:                                                       c0af3e54 c0af3e08
19 3e00: c007d844 c04c867c c0af3e7c c0af3e18 c0011380 ee19e940 c0b89cc8 c0b89cdc
20 3e20: 00000000 00000000 c0098060 ee19e940 ee19e9b0 ed877f40 00000000 00000001
21 3e40: ee02c000 c0af3f00 c0af3e74 c0af3e58 c007db04 c007d7b4 ee19e940 ee19e9b0
22 3e60: c0b5d980 00000000 c0af3e94 c0af3e78 c00811f4 c007dac0 0000002b 00000000
23 3e80: 0000002b 00000000 c0af3eac c0af3e98 c007cd8c c0081108 c0aede24 00000000
24 3ea0: c0af3edc c0af3eb0 c007d0bc c007cd5c c0af3f00 fd10010c c0af5e98 c0af3f00
25 3ec0: fd100100 00000000 c0b8a268 c0af3f58 c0af3efc c0af3ee0 c00093f0 c007d03c
26 3ee0: c0011380 60010013 ffffffff c0af3f34 c0af3f54 c0af3f00 c0015400 c00093c8
27 3f00: 00000001 00000000 00000000 c0024980 c0af2000 c0af4ab8 c075dd90 00000000
28 3f20: 00000000 c0b8a268 c0af3f58 c0af3f54 c0af3f58 c0af3f48 c001137c c0011380
29 3f40: 60010013 ffffffff c0af3f94 c0af3f58 c006c6ec c0011344 c0ac5038 ef7fcb40
30 3f60: c0af4ac4 c0b89970 c0aef940 c0073b80 c0af5d08 c0b99700 c0aeeee8 c0aeb35c
31 3f80: c0757200 ffffffff c0af3fac c0af3f98 c074f860 c006c2d0 c0b99750 c0b99700
32 3fa0: c0af3ff4 c0af3fb0 c0a76d44 c074f7d4 ffffffff ffffffff c0a766f0 00000000
33 3fc0: 00000000 c0ac5038 00000000 c0b99994 c0af4a40 c0ac5034 c0afac80 4000406a
34 3fe0: 414fc091 00000000 00000000 c0af3ff8 4000807c c0a76990 00000000 00000000
35 [<c04c8684>] (test_interrupt) from [<c007d844>] (handle_irq_event_percpu+0x9c/0x30c)
36 [<c007d844>] (handle_irq_event_percpu) from [<c007db04>] (handle_irq_event+0x50/0x74)
37 [<c007db04>] (handle_irq_event) from [<c00811f4>] (handle_fasteoi_irq+0xf8/0x1b8)
38 [<c00811f4>] (handle_fasteoi_irq) from [<c007cd8c>] (generic_handle_irq+0x3c/0x4c)
39 [<c007cd8c>] (generic_handle_irq) from [<c007d0bc>] (__handle_domain_irq+0x8c/0xfc)
40 [<c007d0bc>] (__handle_domain_irq) from [<c00093f0>] (gic_handle_irq+0x34/0x70)
41 [<c00093f0>] (gic_handle_irq) from [<c0015400>] (__irq_svc+0x40/0x88)
42 Exception stack(0xc0af3f00 to 0xc0af3f48)
43 3f00: 00000001 00000000 00000000 c0024980 c0af2000 c0af4ab8 c075dd90 00000000
44 3f20: 00000000 c0b8a268 c0af3f58 c0af3f54 c0af3f58 c0af3f48 c001137c c0011380
45 3f40: 60010013 ffffffff
46 [<c0015400>] (__irq_svc) from [<c0011380>] (arch_cpu_idle+0x48/0x4c)
47 [<c0011380>] (arch_cpu_idle) from [<c006c6ec>] (cpu_startup_entry+0x428/0x4ac)
48 [<c006c6ec>] (cpu_startup_entry) from [<c074f860>] (rest_init+0x98/0x9c)
49 [<c074f860>] (rest_init) from [<c0a76d44>] (start_kernel+0x3c0/0x3cc)
50 Code: e92dd800 e24cb004 e52de004 e8bd4000 (e7f001f2)
---[ end trace 9bdaf8a954bc3572 ]---

スケジューラとの関係

スケジューラはプロセスをtask_struct構造体を用いて管理します。一方で、割込みハンドラは自分のtask_struct構造体は持たず、割込み発生時に実行していたプロセスのスタックを利用します。このことから、割込みハンドラはスケジューラの管理対象外にであることが理解できます。

皆さんは割込みハンドラからスケジューラ (例えばschedule())を呼び出してはいけない(休眠してはいけない)と認識されている方も多いと思います。
実際に呼び出したコードを実行すると下記メッセージとスタックトレースが出力されます。

BUG: scheduling while atomic: プロセス名/PID/プリエンプトカウント

これは"atomicなコンテキストから(実行してはいけない)schedule()を実行しようとしているよ。カーネルに不具合があるよ"という警告メッセージです。
では、なぜ割込みハンドラからスケジューラを呼び出してはいけない(休眠してはいけない)のでしょうか。
この理由をサラッと説明できる方は本節は飛ばしてもらって構いません。
基本的なことですが、書籍などではあまり触れられていないので、ここでは割込みハンドラからスケジューラを呼び出してはいけない理由について述べます。

下図を見てください。
割込みハンドラでスケジューラ.jpg

割込みハンドラ内でschedule( )を呼び出した場合を考えます。この時、スケジューラは優先度に基づいて次に実行するプロセスをディスパッチします。上図の場合では、RTクラスSCHED_FIFOのプロセスBが実行されます。プロセスBの実行後は、nice値に基づいてプロセスCが実行されます(プロセスA、プロセスCのvruntimeの値によってプロセスAが先に実行される可能性もありますが、ここでは考慮しません)。
スケジューラは、task_struct構造体を持たない割込みハンドラは管理対象外でありプロセスAとして扱うため、割込みハンドラの実行はプロセスAの優先度に引っ張られる形になります。つまり、プロセスAが再度ディスパッチされるタイミングまで割込みハンドラの実行が待たされることになります。
このような状態では、割込みハンドラの「緊急度の高い処理を優先して行う」という本来の目的を全く達成できません。
そもそも緊急性が求められる割込みハンドラで休眠するなという話ですが、割込みハンドラ内でmutexやセマフォなど内部で休眠する可能性がある機能で使用しようとする人もいるかもしれないので…。

現在の割込みハンドラの仕組み

現在の割込みハンドラの仕組みは大きく変わりました。
Linux FoundationのコラボラティブプロジェクトにReal-Time Linuxというプロジェクトがあります。
このプロジェクトではPreempt-RT又はRTパッチと呼ばれるリアルタイム応答性向上に取り組んでいます。私が把握している範囲では少なくとも15年前から活動しています。
このプロジェクトの目的は、一言で述べると、リアルタイムで処理したいプロセスのレイテンシをできる限り削減することです。
この目的を実現する為に、本プロジェクトではリアルタイム処理をしたいプロセスの実行を妨げるプリエンプション禁止区間を排除する、というアプローチをとっています。つまり、フルプリエンプティブ(カーネルのどの区間においてもプリエンプション可能)にすることです。
また、リアルタイム処理をしたいプロセスを即座に実行する為に、場合によっては特定の割込みハンドラより優先して実行しないといけない場合もあります。割込みハンドラより優先して実行するということは、スケジューラが割込みハンドラを制御するということです。
しかし、前述の通り、既存の仕組みではスケジューラは割込みハンドラは管理対象外としていました。そこで、Preempt-RTでは、割込みハンドラをスレッド化することで、スケジューラから制御できるように仕組みを変更しました。この機能がmainlineカーネルに取り込まれた版数はアーキテクチャによって異なります。x86では2.6.35、Powerでは3.3、Arm(32bit)では3.12から割込みハンドラのスレッド化を採用しています。

実際に見てみましょう。
以下にpsコマンドの実行結果を示します。
★はSDカードの割込みハンドラに対応するカーネルスレッドです。
割込み毎に"irq/IRQ番号-識別子" という命名規則でカーネルスレッドが生成されます。

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  6.6  0.0  24824  5376 ?        Ss   16:12   0:05 /sbin/init
root         2  0.0  0.0      0     0 ?        S    16:12   0:00 [kthreadd]
: (snip)
root        98  0.0  0.0      0     0 ?        S    16:12   0:00 [irq/28-mmc0] ★
: (snip)

Preempt-RTでは、この仕組み以外にもリアルタイム応答性を向上させるためにフルプリエンプティブにする機能を提供していますが、詳細は別記事で紹介したいと思います。

割込みハンドラの登録処理

割込みハンドラの登録処理を読解することで仕組みがおよそ理解できます。
実際のコードをポイントを絞って追っていきましょう。
ここでは、各種ドライバから割込みハンドラ登録関数として最も使用されているrequest_irq( )を起点に見ていきます。

include/linux/interrupt.h
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
            const char *name, void *dev)
{
        return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}

この関数は、request_threaded_irq( )のラッパー関数です。
request_threaded_irq( )の第3引数にはNULLを設定しています。
次にrequest_threaded_irq( )を見ましょう。

kernel/irq/manage.c
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
                         irq_handler_t thread_fn, unsigned long irqflags,
                         const char *devname, void *dev_id)
{
        struct irqaction *action;
: (snip)

        action->handler = handler;
        action->thread_fn = thread_fn;
        action->flags = irqflags;
        action->name = devname;
        action->dev_id = dev_id;
: (snip)
        retval = __setup_irq(irq, desc, action);
: (snip)
}

この関数のポイントは、上記で抜粋した部分です。
request_irq( )に渡した引数をirqaction構造体に格納して__setup_irq( )を呼び出します。
続いて__setup_irq( )のポイントとなる部分を抜粋します。

kernel/irq/manage.c
static int
__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
        struct irqaction *old, **old_ptr;
        unsigned long flags, thread_mask = 0;
        int ret, nested, shared = 0;
: (snip)
        if (nested) {
: (snip)
        } else {
                if (irq_settings_can_thread(desc)) {
                       ret = irq_setup_forced_threading(new); ★1
                        if (ret)
                                goto out_mput;
                }
        }

        /*
         * Create a handler thread when a thread function is supplied
         * and the interrupt does not nest into another interrupt
         * thread.
         */
         if (new->thread_fn && !nested) {                       2
                ret = setup_irq_thread(new, irq, false);        3
                if (ret)
                        goto out_mput;
: (snip)
}

★1のirq_setup_forced_threading( )を下記に抜粋します。
要点は以下の通りです。
new->flagsの値、つまりrequest_irq( )の第3引数flagsにIRQF_NO_THREAD、IRQF_PERCPU、IRQF_ONESHOTのいずれかを指定している場合はその時点で復帰します。
例えば、タイマ割込みで使用するタイマー デバイスの割込みハンドラを登録する場合、IRQF_NO_THREADを指定してrequest_irq( )を呼び出します。そうすると、本関数ではnew->thread_fnにnew->handlerを設定せずにNULLの状態で復帰します。
一方で、IRQF_NO_THREAD、IRQF_PERCPU、IRQF_ONESHOTを指定していない場合はnew->thread_fnにrequest_irqの第2引数で指定した関数のアドレスをセットし、new->handlerにirq_default_primary_handler( )を設定します。
纏めると下表のとおりです。

new->thread_fn new->handler
flagsにIRQF_NO_THREAD、IRQF_PERCPU_IRQ、IRQF_ONESHOTのいずれかを設定している場合 request_irq( )の第2引数で指定した関数 irq_default_primary_handler( )
上記以外 NULL request_irq( )の第2引数で指定した関数
kernel/irq/manage.c
static int irq_setup_forced_threading(struct irqaction *new)
{
: (snip)
        if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT))
                return 0;
: (snip)
        /* Deal with the primary handler */
        set_bit(IRQTF_FORCED_THREAD, &new->thread_flags);
        new->thread_fn = new->handler;
        new->handler = irq_default_primary_handler;
        return 0;
}

上記内容を踏まえて、__setup_irqの★2を見てください。
new->thread_fnが存在する場合のみ★3のsetup_irq_thread( )を実行します。
では、setup_irq_thread( )で何をしているか見ましょう。

kernel/irq/manage.c
static int
setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary)
{
1        struct task_struct *t;
2        struct sched_param param = {
                .sched_priority = MAX_USER_RT_PRIO/2,
         };

3        if (!secondary) {
4                t = kthread_create(irq_thread, new, "irq/%d-%s", irq, new->name);
5        } else {
6                t = kthread_create(irq_thread, new, "irq/%d-s-%s", irq,new->name);
7                param.sched_priority -= 1;
8        }

9        if (IS_ERR(t))
10                return PTR_ERR(t);

11        sched_setscheduler_nocheck(t, SCHED_FIFO, &param);
: (snip)
}

4行目でカーネルスレッドを生成します。その時の識別子は、"irq/IRQ番号-識別子"で前述のpsコマンドの結果と一致します。
そして、11行目でこのカーネルスレッドのスケジューリングクラスと優先度を設定します。
スケジューリングクラスはRTクラスのSCHED_FIFO、優先度はMAX_USER_RT_PRIOが100なので50になります。

このように、割込みハンドラの登録ごとにrequest_irq( )の第3引数flagsにIRQF_NO_THREAD、IRQF_PERCPU、IRQF_ONESHOTのいずれも設定されていない場合は、それぞれの割込みに対応する割込みハンドラ用スレッドを生成します。逆にこれらのフラグのいずれかが設定されている場合はスレッドを生成しません。
タイマー割込みなどプロセスの実行より常に優先すべき割込みは従来同様に割込み発生時に実行していたプロセスのスタックを使用して実行します。従って緊急度が高い割込みはIRQF_NO_THREADを設定します。

割込みハンドラの実行

ここでは割込みハンドラの実行時の動作について見ます。
ポイントを絞って記載したいと思います。
Linuxでは、
(1)アーキ固有割込み入口処理
(2)アーキ共通割込み入口処理
(3)割込みハンドラ
(4)アーキ共通割込み出口処理
(5)アーキ固有割込み出口処理
があります。

ここでは(2)の後半と(3)に注目してコードを見てみます。
(2)の一番最後に呼ばれる関数((3)を呼び出す関数)はhandle_irq_event( )です。
この関数ではhandle_irq_event_percpu( )を呼び出します。

kernel/irq/handle.c
irqreturn_t handle_irq_event(struct irq_desc *desc)
{
        irqreturn_t ret;
: (snip)

        ret = handle_irq_event_percpu(desc);
: (snip)
}

handle_irq_event_percpu( )は以下の通りです。

kernel/irq/handle.c
irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
{
        irqreturn_t retval;
        unsigned int flags = 0;

        retval = __handle_irq_event_percpu(desc, &flags); ★

        add_interrupt_randomness(desc->irq_data.irq, flags);

        if (!noirqdebug)
                note_interrupt(desc, retval);
        return retval;
}

本関数では__handle_irq_event_percpu( )を呼び出します。(★)

kernel/irq/handle.c
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{
 1        irqreturn_t retval = IRQ_NONE;
 2        unsigned int irq = desc->irq_data.irq;
 3        struct irqaction *action;

 4        record_irq_time(desc);

 5        for_each_action_of_desc(desc, action) {
 6                irqreturn_t res;

 7               trace_irq_handler_entry(irq, action);
 8               res = action->handler(irq, action->dev_id);
 9               trace_irq_handler_exit(irq, action, res);

10                if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pS enabled interrupts\n", irq, action->handler))
11                        local_irq_disable();

12                switch (res) {
13                case IRQ_WAKE_THREAD:
                        /*
                         * Catch drivers which return WAKE_THREAD but
                         * did not set up a thread function
                         */
14                        if (unlikely(!action->thread_fn)) {
15                                warn_no_thread(irq, action);
16                                break;
17                        }

18                        __irq_wake_thread(desc, action);

                        /* Fall through - to add to randomness */
19                case IRQ_HANDLED:
20                        *flags |= action->flags;
21                        break;

22                default:
23                        break;
24                }

25                retval |= res;
26        }

27        return retval;
  }

まず8行目に注目してください。
ここで割込みハンドラを実行します。
8行目で実行する関数と復帰値を纏めると下表のようになります。

action->handler関数 復帰値
flagsにIRQF_NO_THREAD、IRQF_PERCPU_IRQ、IRQF_ONESHOTのいずれかを設定している場合 request_irq( )の第二引数で指定した関数 (正常終了した場合)IRQ_HANDLED
上記以外 irq_default_primary_handler( ) IRQ_WAKE_THREAD

参考までにirq_default_primary_handler( )を示します。
常にIRQ_WAKE_THREADを返すのみの関数です。

kernel/irq/manage.c
static irqreturn_t irq_default_primary_handler(int irq, void *dev_id)
{
        return IRQ_WAKE_THREAD;
}

その後の12行目のswitch文で、スレッド化された割込みハンドラとされていない割込みハンドラでシーケンスが異なります。
スレッド化されていない従来同様の割込みハンドラは20、21行目を実行します。
スレッドした割込みハンドラは14 - 18行目を実行します。
ポイントは18行目です。

kernel/irq/manage.c
void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
{
: (snip)
        wake_up_process(action->thread);
}

wake_up_process( )で対象の割込みハンドラ用スレッドの起床要求をします。
wake_up_process( )の動作は、別記事で紹介した通り、対象のプロセスをスケジューラの実行キューに繋ぎます。従って、ここで起床要求をしても直ぐにはスケジューリングが行われず、(5)アーキ固有割込み出口処理直後にスケジューリングが行われ、割込みハンドラ用スレッドに制御が渡ります。

注意事項

システム設計が複雑になります。デフォルトで割込みハンドラ用スレッドがSCHED_FIFO、優先度50で実行されていることを考慮した上でプロセスの優先度を決定したり、割込みハンドラをスレッド化させるべきか否か、といった従来の仕組みでは考える必要がなかった要因まで検討しなければいけません。
例えば、プロセスの優先度を最高優先度付近に設定すると、当然、デフォルトの割込みハンドラ用スレッドより当該プロセスの実行が優先されます。
このことから、リアルタイム応答性に関連する割込み/プロセス、その他の割込みハンドラ用スレッド/プロセスの優先度に関する方針を上流工程で設計しておく必要があります。

他の記事:【読解入門】Linuxカーネル (概要編)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む