- 投稿日:2019-11-27T23:06:10+09:00
ハードディスクのデータを全消去する方法
今まで使用していたディスクを、次の人に申し送るのに、ディスクのデータを全消去して渡したい時があると思います。
そんなときに使えるのが、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 を抜いて、マシンを再起動してみてください。すっきり、気持ちいいですね。
- 投稿日:2019-11-27T21:55:28+09:00
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)
ストレージ: 50GBProxyの設定
とりあえず、.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_7yum install docker device-mapper-libs device-mapper-event-libs systemctl start docker.service systemctl enable docker.serviceDockerにもProxyの設定をしておきます。
mkdir -p /etc/systemd/system/docker.service.d vi /etc/systemd/system/docker.service.d/http-proxy.confhttp-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 firewalldsetenforce 0 sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/configswapも無効にしておきます。
sudo swapoff -a/etc/fstabの編集も忘れずに。
UUID=d06071e3-4760-4d1b-98d3-891566cbf0c3 / ext4 defaults 0 0 #/swap.img none swap sw 0 0Kubernetesの導入
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* EOFkubelet、kubeadm、kubectlを導入します。
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes systemctl enable --now kubeletkubeadmを使ってkubernetesの構成を行います。
最初は、dry-runをしてエラーがないことを確認した後、本番にのぞみましょう。
"--pod-network-cidr="は、kubernetesクラスター内で使うCIDRを指定します。kubeadm init --pod-network-cidr=192.168.0.0/16 --dry-runkubeadm 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
- 投稿日:2019-11-27T21:40:00+09:00
シェルスクリプトでディレクトリ移動を自動化したぞ!
Webアプリを作ってるとき毎回起動するときdocker-composeでコンテナ立ち上げるのめんどくさいので自動化しました。
- 使用OS centOS7
- ライブラリ laradock
- ルート直下にディレクトリを分かりやすいように作ってその中に touch docker_compose_start.sh というファイルを作成
docker_compose_start.sh#!usr/bin/bash cd /project/laradock docker-compose start
実行できるようにファイルの権限を変える
chmod 755 docker_compose_start.sh作ったディレクトリの中でファイルを実行する
./docker_compose_start.shこれでコマンド一回でコンテナが立ち上がるようになる
- 投稿日:2019-11-27T21:22:58+09:00
【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.timecardcat
ファイルの中身を標準出力で表示するコマンド。
中身が多いと標準出力が圧迫されて、お葬式になる。$ cat wagahai-ha-cat.book 吾輩は猫である 夏目漱石 吾輩わがはいは猫である。名前はまだ無い。 ...head/tail
ファイルを先頭または末尾から行数や文字数を限定して出力する。
まさに、頭と尻だけを出すためのコマンド。
「頭隠して尻隠さず」のことわざに立ち向かいたいときにおすすめ。# タイトルと作者の先頭2行だけが知りたい人向け $ head -n 2 wagahai-ha-cat.book 吾輩は猫である 夏目漱石 # オチの最後2行だけで全て分かる人向け # 最後の1行は改行 $ tail -n 2 wagahai-ha-cat.book 次第に楽になってくる。苦しいのだかありがたいのだか見当がつかない。水の中にいるのだか、座敷の上にいるのだか、判然しない。どこにどうしていても差支さしつかえはない。ただ楽である。否いな楽そのものすらも感じ得ない。日月じつげつを切り落し、天地を粉韲ふんせいして不可思議の太平に入る。吾輩は死ぬ。死んでこの太平を得る。太平は死ななければ得られぬ。南無阿弥陀仏なむあみだぶつ南無阿弥陀仏。ありがたいありがたい。おまけ
clear
標準出力をキレイキレイするコマンド。
おきのどくですが 標準出力は きえてしまいました$ clear
まとめ
記事のテイストをいつもと変えてみた。
Linuxコマンドも地味に楽しい。
スクリプト言語には、相性もいい気がする。
- 投稿日:2019-11-27T20:52:42+09:00
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.pubcatコマンド
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アドレス]:~/.sshAWSの場合
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サーバにログイン成功
- 投稿日:2019-11-27T20:18:09+09:00
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 startOMSAの利用
OMSAが起動した状態でWebブラウザから以下のURLへアクセスする。
- https://<ホスト名 or IPアドレス>:1311/
以下のログイン画面が出るので、ユーザとパスワードを入力する。
- ログインをすると、HWの状態やログを確認することが可能となる。
- 2枚目のキャプチャはストレージの状態を確認したサンプル
CLIの使い方
- OMSAをインストールすると、CLIでHWの状態確認を行うことが可能になる。
- 詳細は別途、整理予定。
- 投稿日:2019-11-27T15:53:58+09:00
Windows10のWSLでLinuxを使う手順
Windows10のWSLでLinuxを使う手順
WSLを有効にする
Win+Rで「ファイル名を指定して実行」ダイアログを開く
control
と入力して<ENTER>
「プログラムと機能」をクリックして、表示されたウィンドウから
「Windowsの機能の有効化または無効化」をクリック「Windows Subsystem for Linux」のチェックを入れてOK
再起動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のURLaptのproxy設定(ファイルは新規に作成する)
/etc/apt/apt.confAcquire::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コマンドチートシート - Qiitagccとか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-devgitからdotfilesとかダウンロード
gitのSSL無視。必要な場合のみ。
$ git config --global http.sslVerify falsegitから設定ファイル等をクローンしてくる。必要な場合のみ。
$ git clone htts://github.com/<user_name>/<repository_name>.git
- 投稿日:2019-11-27T13:29:59+09:00
開発者なら知っておくべき 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
コマンドは各ファイルの文字列を検索します。また、改行文字で区切られたパターンも検索し、パターンに一致する行をそれぞれ出力します。grep
でファイル内の React という文字列を検索する
-i
オプションを使用すると、指定したファイル内の大文字と小文字を区別せずに文字列を検索できます。この場合「REACT」、「REact」、「react」などの文字列を検索します。$ grep -i "REact" file
-c
(count)オプションを使用すると、指定された文字列/パターンがファイル内で何回記載されているかがわかります。$ grep -c "react" index.jsgrep -c
コマンドで react の 記載回数をカウント
これは私がインターネットで見つけた、grep
コマンドに関する楽しくてためになるイラストです。
Source: Wizard Zinesまた、異なるコマンドの
egrep
およびfgrep
は、それぞれgrep -E
およびgrep -F
と同様のコマンドです。これらのバリアントは非推奨ですが、下位互換性のために提供されています。
grep
では多くのことを行えます。--より深く理解するためにはこのドキュメントを読んでください。2. ls
$ ls
ls
コマンドはパス内のファイルとディレクトリを一覧表示します。パス名がファイルの場合、ls
コマンドは要求されたオプションに従ってファイルに関する情報を表示します。パス名がディレクトリの場合、
ls
コマンドはディレクトリ内のファイルとその中のサブディレクトリに関する情報を表示します。ls
でパス内のすべてのディレクトリとファイルを表示
フォルダが青色で表示されているのに対し、ファイルはグレーで表示されていることに気づいたかもしれません。これは、フォルダとファイルを区別するのに役立ちます。3. pwd
$ pwdpwd
で作業ディレクトリの絶対パスを表示
pwd
コマンドは、現在の作業ディレクトリを出力するコマンドです。現在の作業ディレクトリの完全なシステムパスを標準で出力します。オプションで現在のディレクトリの完全な物理パスを表示できますが、デフォルトでは、pwd
コマンドはシンボリックリンクを無視します。4. cat
$ cat somefile.jscat
でファイルの内容を表示
cat
コマンドには、テキストファイルに関する3つの関連機能があります。
- テキストファイルの内容を表示する
- テキストファイルのコピーを結合する
- 新しいテキストファイルを作成する
cat
コマンドの最も一般的な使い方は、ファイルの内容を読み取ることであり、多くの場合この目的に最も便利なコマンドです。以下の例では、
cat
の標準出力は、出力リダイレクト演算子(>
で表されます)を使用してfile2にリダイレクトされます。$ cat somefile > somefile2cat
を使ってファイルを作成する5. echo
$ echo "some text"Linux の
echo
コマンドは、引数として渡されたテキスト/文字列を表示するために使用されます。echo
コマンドは主にシェルスクリプトやバッチファイル内で使われ、ステータス情報のテキストを画面やファイルに出力します。6. touch
$ touch somefile
touch
コマンドは空ファイルを作成するために使用されます。touch
コマンドは、ユーザーがファイル作成時点ではデータを保存する必要がない場合に使用されます。
touch
で新しいファイルを作成
上の図ではtouch
を使ってファイルを作成し、cat
でファイルの内容を確認しています。新しく作成されたindex2.jsファイルは空なので、cat
は何も返しません。以下は
cat
とtouch
の主な違いです:
cat
— コンテンツを含むファイルを作成するために使用されます。touch
— コンテンツ無しまたは空ファイルの状態でファイルを作成します。touch
コマンドで作成したファイルは空だということに注意してください。このコマンドは、ユーザーがファイル作成時点で保存するデータがない場合に便利です。7. mkdir
$ mkdir some-directory単語から推測できる通り、
mkdir
は現在のアクティブパスに新しい空のディレクトリを作成します。テキストエディターやGUI上でクリックする代わりに、このコマンドを使用して新しいフォルダーを作成します。
mkdir
で新しいディレクトリを作成
注:前述のls
コマンドでディレクトリ内をどのように覗くことができるか確認してみてください。7.1 rm
$ rm someFile
rm
はremoveの略で、まさにそのまま言葉通りのことをします。つまり、ファイルを取り除く、別の言葉で言えば、削除します。rm
コマンドでファイルを削除
デフォルトでは、rm
コマンドはディレクトリを削除しません。ディレクトリを削除するには、(rm) -rf
オプションを渡す必要があります。$ rm -rf some-directoryrm -rf
でディレクトリを削除(ディレクトリ削除のためのオプションを付与)
注:このコマンドにより、ディレクトリにコンテンツが含まれているかどうかに関係なくディレクトリが無条件に削除されます。7.2 rmdir
$ rmdir some-directory
rmdir
コマンドはディレクトリの内部にコンテンツがない場合にディレクトリを削除します。rmdir
でからのディレクトリを削除8. tail
$ tail somefile
tail
コマンドはファイルの最後の部分(テール)を読み取り出力します。
デフォルト(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 29. wget
$ wget someurl
wget
(GNU Wget)は 最も広く使用されているインターネットプロトコルであるHTTP、HTTPS、FTP、およびFTPSを使用してファイルを取得するための、フリーソフトウェアパッケージです。ノンインタラクティブなコマンドラインツールであるため、スクリプト、CRONジョブ、X-Windowsサポートのないターミナルなどから簡単に呼び出すことができます。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
コマンドによりファイルまたはディレクトリをすばやく検索できます。数百以上のファイルや複数のディレクトリを持つ、大きなプロジェクトで作業する場合に便利です。
find
でディレクトリ内のindex.js
という名前のファイルすべてを見つける特定の種類のファイルを検索する
find
コマンドを使用すると、ディレクトリ(およびそのサブディレクトリ)内で同じタイプのファイルを検索することもできます。例えば以下のコマンドは現在の作業ディレクトリ内のすべての .js ファイルを検索します。$ find . -name "*.js"components
ディレクトリですべての .js ファイルを見つける11. mv
$ mv somefile /to/some/other/path
mv
コマンドは、ファイルまたはディレクトリをある場所から別の場所に移動します。このmv
コマンドは、単一ファイル、複数ファイル、およびディレクトリの移動をサポートしています。some-directory を components からutils に移動する最後に..
ここまで読んでいただきありがとうございます。何か得るものがあったなら幸いです。もっと便利なコマンドを知っている場合は是非共有していただき、一緒に成長していきましょう。
-貪欲であれ。好奇心旺盛であれ。-翻訳協力
Original Author: Indrek Lasn
Thank you for letting us share your knowledge!この記事は以下の方々のご協力により公開する事が出来ました。
改めて感謝致します。
選定担当: Yumika Tomita
翻訳担当: @upaldus
監査担当: @nyorochan
公開担当: @miyonori0812ご意見・ご感想をお待ちしております
今回の記事は、いかがだったでしょうか?
・こうしたら良かった、もっとこうして欲しい、こうした方が良いのではないか
・こういったところが良かった
などなど、率直なご意見を募集しております。
いただいたお声は、今後の記事の質向上に役立たせていただきますので、お気軽にコメント欄にてご投稿ください。Twitterでもご意見を受け付けております。
みなさまのメッセージをお待ちしております。
- 投稿日:2019-11-27T12:26:40+09:00
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の設計思想を考えたことが無く、良い機会になりました。
この記事を読んでくださった皆様も、ぜひ普段お使いのコマンドやツールの作者の意図や意志、
その歴史を、原典まで遡って、追いかけてみてはいかがでしょうか。
- 投稿日:2019-11-27T10:58:22+09:00
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/sunvtslspci 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
- 投稿日:2019-11-27T10:17:37+09:00
【読解入門】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種類の割込みハンドラの仕組みが用意されています。ハードウェア割込みハンドラ
緊急性の高い必要最低限の処理を実装します。
キーボードのキーを押下した場合の割込みを例で考えてみましょう。
ハードウェア割込みハンドラはキーボード デバイスの割込みを刈り取った後、押下されたキー情報を取得して、上位レイヤに通知して終了します。
押下されたキーに対するアクション(画面に表示する処理など)はハードウェア割込みハンドラでは行いません。
私なりの基本的な考え方は、至ってシンプルです。
割込みを上げたハードウェアにアクセスする処理はハードウェア割込みハンドラで、それ以外の処理はソフトウェア割込みハンドラで、を基準に考えています。ソフトウェア割込みハンドラ
Linuxを扱う書籍、Webでは様々な呼び方がされています。ソフトウェア割込み、SoftIRQ、割込みの遅延処理など。
本記事ではこのソフトウェア割込みハンドラについてそれほど触れる予定もないので、この機能については別途記事を書きたいと思います。
割込み処理のうち、緊急度がそれほど高くなく、遅れて実行される処理と思っていただければ良いと思います。従来の割込みハンドラの仕組み
以降はハードウェア割込みハンドラを「割込みハンドラ」と記述します。
割込みハンドラが使用するスタック
Linuxの割込みハンドラは、自身を実行する為のスタックを持ちません(少なくともx86、Arm(32bit)、Powerアーキテクチャにおいては)。下図の通り、割込みが発生した時点に実行していたプロセスのカーネルスタックを使用します。
この図だけではイメージが湧かないと思いますので、実際の割込みハンドラ実行時のスタックの中を確認してみましょう。
今回は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()を実行しようとしているよ。カーネルに不具合があるよ"という警告メッセージです。
では、なぜ割込みハンドラからスケジューラを呼び出してはいけない(休眠してはいけない)のでしょうか。
この理由をサラッと説明できる方は本節は飛ばしてもらって構いません。
基本的なことですが、書籍などではあまり触れられていないので、ここでは割込みハンドラからスケジューラを呼び出してはいけない理由について述べます。割込みハンドラ内で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.hstatic 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.cint 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.cstatic 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.cstatic 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.cstatic 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, ¶m); : (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.cirqreturn_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.cirqreturn_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.cirqreturn_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.cstatic 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.cvoid __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で実行されていることを考慮した上でプロセスの優先度を決定したり、割込みハンドラをスレッド化させるべきか否か、といった従来の仕組みでは考える必要がなかった要因まで検討しなければいけません。
例えば、プロセスの優先度を最高優先度付近に設定すると、当然、デフォルトの割込みハンドラ用スレッドより当該プロセスの実行が優先されます。
このことから、リアルタイム応答性に関連する割込み/プロセス、その他の割込みハンドラ用スレッド/プロセスの優先度に関する方針を上流工程で設計しておく必要があります。