インストールしたシステムについてのFAQ。

ログイン、ログアウト

ブート手順についてのFAQはBootFAQsに移動しました。

rootユーザーって何?

rootユーザー(スーパーユーザー)はUNIXに用意されている特別なユーザー。rootユーザーには、マシンを完全に掌握できるroot権限(管理者権限)が与えられる。

UNIXでは通常、そのユーザーにとって操作できるように所有権とパーミッションが設定されているファイルしか操作することができないが、root権限の元で実行されたプログラムは、ファイルの所有権に関わらずあらゆることを実行することができる。

そのため、全てのユーザーにとって共有されるシステム一般のファイルでも、rootになれば改変できる。

rootユーザーは非常に強力なので、常に使っているとあらぬ操作でシステムを動作不能にさせてしまう可能性がある。通常は普通のユーザーで操作を行い、システム全体を調整する必要があるときだけrootユーザーを使おう。

なぜ root で作業をしてはいけないのですか

root ユーザーに切り替えたい (su)

普通のユーザーでログインしてるときに root や他のユーザーに切り替わりたいときは、 su を実行すると別のユーザーになった上で新しいシェルを立ち上げてくれる。

$ su -
Password: (root のパスワードを入力)
# (rootのシェルになった)

root のシェルではコマンド入力行の $ が # と表示される。

# exit
$ (ユーザーに戻る)

前のユーザーに戻るときは exit でシェルを終了させる。

"root" に二つの意味があるみたいなんですが・・。

root というとシステム管理権限のあるスーパーユーザを指すことが多いけど、ファイルシステムの一番根元の事("/")も root と呼ばれる

というわけで root ユーザ(もしくはスーパーユーザ)、ルートディレクトリなどと区別して記述するといいかと。

コマンド入力例の $ とか % とか # って何ですか?

コマンドを打ち込むユーザーの権限 (一般ユーザー/root ユーザー) のことです。

$ %一般ユーザーでの操作。#root 権限を持った スーパーユーザー (root ユーザー) での操作を示します。

相手に一般ユーザーでの作業なのかスーパーユーザーでの作業なのかを判別するのに使われます。

~/ って何ですか?

~/ はユーザのホームディレクトリのことです。例えば hoge という名前のユーザなら、/home/hoge が ~/ となります。

$ cd ~/
$ pwd
/home/hoge

(ただ単に cd とだけ打てばホームディレクトリに行けるけど、あくまで例として。)

終了/再起動はどうやったらできますか? (shutdown)

shutdown を使う。実行する前に root になっておこう。停止する場合は -h、再起動する場合は -r オプションをつける。

# shutdown -h now
# shutdown -r now

halt、reboot などのコマンドも使えます。終了時に root になる必要があるのは、root で実行するサーバーなどのデーモンを終了させる必要があるからです。

ログイン時やパスワード設定時にパスワードを入力しても何も表示されません。

コンソール上の各種パスワード入力プロンプトでは、入力した文字の情報が他の人にわからないように何も表示されないようになっています。 文字が表示されなくてもそのままかまわずパスワードを打ち、続いて Enter キーを打ちましょう。

打ち間違えたり、もう一度最初から入力したい時は Ctrl+u (=行削除) キーを押すと、入力した文字をすべて消去してパスワードを再入力することができます。

パスワードを削除したい (vipw)

vipw コマンドで:と:の間にはさまれた意味不明な文字列を削除する。vipw (=vi) の使いかたはしらべてね。

/etc/shadow を直接編集してもいいけれどもお薦めしない。そもそもパスワードを削除すること自体お薦めしない。


コンソール

端末エミュレータやらターミナルって何ですか?

簡単に言うと端末画面をエミュレートするソフトのこと。

決められた数しか開けない実際の端末とは違って好きなだけウィンドウを開けるのも利点の1つ。*1

端末エミュレータ(ターミナル)には色んな種類があるので代表的な物をいくつか紹介します。 X Window System がインストールされているならば、どれか一つはインストールされていることでしょう。

定番

  • xterm (X Window System 付属)

デスクトップ環境に付いてる奴

コンソールやターミナルの作業の記録を取りたい (script, tee)

script コマンドを使います。

script コマンド
記録を開始 $ script 記録保存用ファイル
記録を終了 $ exit

あるいは tee コマンドを使うと、特定のコマンドだけ出力を記録しておけます。

tee コマンド
コマンドの出力を記録 $ コマンド | tee 記録保存用ファイル

ビープ音(ベル)を消したい。

逆に beep というパッケージを入れるとビープ音をコマンドで任意に鳴らせる。


コマンドの基本

コマンドの打ち込み方が分かりません。

端末エミュレータ (ターミナル) というのを開いたあとで、コマンドをキーボード入力して Enter キーを押すと実行できる。

コマンド入力例の$/%/#はコマンドを打ち込むユーザの権限のことなので打つ必要なし。#がついたコマンドは root ユーザー になったあとで実行すること。

先生!! CUI の基礎的な使い方すらわかりません!

以下のページで簡単に解説してあります。

コマンドは一字一句全部入力しなければいけないのですか?

Tabキーを押してコマンド補完を使ってみよう。Bash入門の コマンド補完機能を使おう 参照。

何をどうしていいのやら分からないレベル

質問したものの冷たく「 man (オンラインマニュアル) 読め 」と言われて途方にくれた場合どう生き残るか。

とりあえず、Red Hat Linux 入門ガイドの シェルプロンプトの基本 を読んでみよう。

??をしたいんだけどどうすればいいのだろう?

日経 LinuxLinux コマンド逆引き大全 というすんごいページがあるので参考にしよう。左下の Linux の基礎というところから読めます。閲覧にはユーザー登録が必要なので登録するべし。(無料)

どんなコマンドがあるんだろうか?

日経 LinuxLinux コマンド集 があるので参考にしよう。

ジャンル別になっているのでペラペラと読んでみると新たな発見があるかも。

このコマンド、どんなオプションがあるんだろうか?

JM を読んでみましょう。JM はコマンドについているオンラインマニュアルを日本語に翻訳してくれているありがたいプロジェクトです。

たとえばファイルをコピーするコマンド "cp" を検索するとこんな風に表示してくれます

また、JM では最新のバージョンのコマンドに翻訳が追い付いていない場合があるので、端末エミュレータman コマンドを使えるようになっておくといいでしょう。

$ man コマンド名

man コマンドの使い方を表示する方法は以下の通り。

$ man man

英文のものを表示したい場合は以下のように環境変数 LANG を一時的に変更して実行します。

$ LANG=C man man

man は UNIX 系 OS のほとんどで採用されている伝統的なマニュアルシステムですが、GNU 系のソフトウェアだと info というのを標準採用していたりもします。

$ info info

man も info も表示されない場合は、コマンドに --help とつけて呼び出すとヘルプが表示されることも。

$ cat --help

man ページにある番号の意味は何?

$ man bash

とすると BASH(1) と表示されます。この数字はセクションと呼ばれるものです。

数字の詳細については JM Project のセクションとは?参照のこと。

例えば mount コマンドに関するマニュアルは 28 の異なるセクションのマニュアルが用意されています。

$ man 2 mount
$ man 8 mount

上記のようにセクションを指定すると見ることができます。

コマンド補完を使おう。

コマンド補完を使うと正確に、そして早く入力ができるようになります。

詳細は初心者のためのシェル(bash)入門を参照のこと。

コマンドを実行しようとすると command not found と言われます。

ターミナルでコマンドを実行しようと hoge と入力しても、bash: hoge: command not found などと言われてしまう場合。

原因は以下の2通りが考えられます。

1. コマンドがそもそも存在しない。

この場合、そのコマンドの実行ファイルをインストールすれば使えるようになるはず。

2. コマンドは存在しても、PATH に含まれるディレクトリ以外の場所にある。

コマンドの実行ファイルが存在していても、環境変数 PATH の一覧に含まれてるディレクトリにないと見つけられない。

PATH の設定を確認するには echo $PATH と実行する。もし、実行ファイルがこれ以外の場所にあれば /home/huga/hoge とフルパスで打てば実行できる。*2

/sbin/usr/sbin にある管理用のコマンドの場合は、root でない一般ユーザの PATH には含まれないので、一般ユーザはフルパスで打たない限り実行できない。

su で一般ユーザから root に切り替る際は、 su - とハイフンをつけずに su と実行すると、一般ユーザの環境設定がそのまま使われてしまうので注意すること。(参考)

なお、現在のディレクトリに hoge という実行ファイルがあったとして、それを実行したいときは ./hoge と打ち込む。("." は現在のディレクトリの意)*3

/usr/local/hoge1 とか /usr/local/hoge2 とかに実行ファイルを入れている場合、全てを PATH に追加するのが面倒なら /usr/local/bin などにシンボリックリンクを張る手が使えます。


Tips

フロッピーや CD-R に収まらないファイルを分割、結合したい。(split, cat)

分割は split コマンド、結合は cat コマンドが簡単です。

split -b 分割サイズ 分割するファイル 分割後のファイル先頭につける文字列 hoge.tar.gzを1440KBの「hoge_splited」で始まるファイルに分割してみる:

$ split -b 1440k hoge.tar.gz hoge_splited. 
$ ls 
hoge.tar.gz hoge_splited.aa hoge_splited.ab hoge_splited.ac

cat 結合したいファイル >> 結合後のファイル

$ cat huga_splited.aa huga_splited.ab >> huga.tar.gz

あるいは * を用いて

$ cat huga_splited.* > huga.tar.gz
分割/結合 コマンド
split (分割) $ split -b 分割サイズ 分割するファイル 分割後のPREFIX
cat (結合) $ cat 結合するファイルのPREFIX .* >> 結合後のファイル名

分割サイズのデフォルト単位はバイトだけど、サイズの後に km をつければKB(=1024B)やMB(=1024KB)になります。

テキストファイルの中の文字列を検索したいんですが

grep コマンドを使うと、指定した文字列を含む行を画面に表示します。ディレクトリ内のファイル全てから検索する場合は -r オプションをつけます。

grep コマンド
ファイルから検索 $ grep 検索する文字列 ファイル
ディレクトリから検索 $ grep -r 検索する文字列 ディレクトリ

ディレクトリから検索するときは「ファイル名:一致する行」のように表示されます。

テキストファイルの中の文字列を別の文字列に置換したいんですが

sed コマンドを使うと、ファイルの中の特定の文字列を別の文字列に置換して画面に表示します。

sed コマンド
置換 $ sed -e "s/置換したい文字列/置換後の文字列/g" ファイル

-e オプションを複数指定すると複数置換します。出力を表示せずにファイルに保存したい場合はリダイレクトします。

コマンド表示結果の2番目や3番目の部分だけ抜き出したいんですが (awk)

awk コマンドを使うと、空白などで区切られた表示結果の2列目や3列目の部分だけを抜き出して画面に表示します。

例えば コマンド | awk '{print $2}' と入力すると、コマンドの出力のすべての行のうち、何か(デフォルトは空白)で区切られている 2 番目(=$2)だけを抜き出して表示します。

ファイル名の文字コードを一括変換したい

SMBCHARTOOL が便利です。

  • 日本Sambaユーザ会 - SMBCHARTOOL

    SMBCHARTOOLは、Sambaのコンパニオンツールで、Samba サーバ上の日本語ファイル名の文字コードを一括変換することで、Sambaサーバを運用する管理者を支援するツールです。
    現在は euc, hex, jis, cap, sjis の各文字コードに対応しています。また、変換だけでなく旧バージョンにおける文字化けに対しても、修復します。

convmv ってのも。

ファイルやディレクトリの違い(差分)を調べたい (diff)

diff コマンドで差分を調べられます。二つのディレクトリにあるファイルの差分を調べたい時は -r オプションをつけます。

diff コマンド
2つのファイルの差分を調べる $ diff ファイル1 ファイル2
2つのディレクトリの差分を調べる $ diff -r ディレクトリ1 ディレクトリ2

設定ファイルを書き換えたい

各種テキストエディタ を使用します。 Unix 系 OS では vi系エディタを使うのが伝統ですが、初心者には難しいかもしれません。Linux では nano が簡単です。

GUI のテキストエディタもありますが、X サーバが立ち上がらなくなってしまった時にも困らないよう、 CUI のテキストエディタに慣れておいた方がよいでしょう。

システムのタイムゾーンを変更したい。

タイムゾーンを変更するには、root になって以下のコマンドを実行します。

タイムゾーン変更 コマンド
Red Hat 系 # /usr/sbin/timeconfig
Debian 系 # /usr/sbin/tzconfig

知らない間にcoreという名前のファイルができてしまった

知らない間にcoreという名前のファイルができてしまった(@IT)

load average はどうやって調べるんですか? (top, uptime, xload)

ロードアベレージを調べるには top , uptime , xload などを使います。

異様にメモリを食っているようなのですが、問題ないでしょうか?

たいていの場合、使っていない実メモリをキャッシュとして有効活用しているだけなので、問題はありません。

free コマンドを実行してメモリの使用状況を確認してください。

$ free
             total       used       free     shared    buffers     cached
Mem:        256568     251608       4960          0      16992      99836
-/+ buffers/cache:     134780     121788
Swap:       196520      29488     167032

出力の2行目 (Mem: の行) を見ると、free の欄が 4960 となっていて total に比べてかなり小さく、メモリ使用率がかなり高くなっているように見えます。

が、キャッシュとして使用している分を除いた値 (3行目の free の欄) を見ると121788 なので、半分近く空いています。この場合はそれほど問題ではありません。メモリが必要になるとキャッシュ部分がクリアされて、使用できるようになります。

  • Linux のメモリー管理(メモリ−が足りない?,メモリーリークの検出/防止)

    Linux(っていうか UNIX かな?) では, 各プロセスにメモリを割り振った残りをバッファ(buffer)とキャッシュ(cache)に利用して, ディスク入出力の負荷を減らしている. そのため, free コマンド等で見える残りメモリ−(free)は 1M 程度の瞬間的な使いまわしに対処する程度しか残っていない事が多い.
    この例では, 実質的な残りメモリ−は, バッファとキャッシュに転用された分も考慮すると free+buffers+cached で計算できる. 上の例で云うと free+buffers+cached = 1628+20112+126848 = 148588. まだまだ, メモリ−には余裕がある.


知っているとちょっと便利なコマンド

ファイルの中身を観覧: less

ファイルの内容の閲覧。

$ less [ファイル名]

スペースキーで進む、bキーで戻る、qキーで終了。似たようなのに more (次に進むだけで、元に戻れない) とか lv (国際化版) とかもある。

システム情報の表示: uname

システム (OS 名など) の情報を表示。

$ uname

すべての情報を表示させるには、 -a オプションを使用。

$ uname -a

現在時刻を表示: date

現在時刻を表示。

$ date

カレンダーを表示: cal

カレンダーを表示。

$ cal

数ヵ月分まとめて表示させるには、 -* オプションを使用。


Linux カーネル 2.6 についての話題や注意点など。

参考 URL

ここより Linux Kernel 2.6 関連 の方が情報が多いです。

Linux カーネル、デバイスドライバについて詳しく知りたい。

Linux カーネル付属文書の翻訳はどこかにない?

解説 リンク
JF: Index of Linux Kernel 2.2 Documentation http://linuxjf.sourceforge.jp/JFdocs/kernel-docs-2.2/
JF: Index of Linux Kernel 2.4 Documentation http://linuxjf.sourceforge.jp/JFdocs/kernel-docs-2.4/
JF: Index of Linux Kernel 2.6 Documentation http://linuxjf.sourceforge.jp/JFdocs/kernel-docs-2.6/
JF: Configure.help Japanese translations. http://linuxjf.sourceforge.jp/JFdocs/Configure.help/

カーネル 2.6 にアップグレードしてみたところ、X上でターミナルが立ち上がらなくなりました。

Unable to open a suitable terminal device.とエラーメッセージが出る。

カーネルコンフィグで

File Systems >
  Pseudo filesystems >
    [*] /dev/pts

これで解決。

NPTL を採用したカーネルを使うとあるソフトが動かなくなってしまいました

NPTL は古い Linux Threads 実装とバイナリで互換性があるようになっていますが、古い Linux Threads の実装で POSIX 標準以外の実装の部分を使用しているソフトウェアの場合、NPTL の環境では修正が必要になります。

NPTL でソフトがうまく動作しない場合は環境変数 LD_ASSUME_KERNEL を設定すると古い Linux Threads を使えます。

古い Linux Threads を使う 設定値
フローティングスタックあり 2.4.1
フローティングスタックなし 2.2.5

今のところ上記二種類の設定があるようです。

hoge というプログラムを使うときに設定したい場合は以下のようにすれば一時的に環境変数を設定して実行する事ができます。(bash の例)

LD_ASSUME_KERNEL=2.2.5 hoge

カーネルの仕組み

コンテキスト切り替え

カーネルはとても小さな時間で次々とプロセスを切り替えることで プログラムの並列実行を可能としている。

具体的には、レジスタの内容をtask_structという構造体に退避し、 プロセスを安全に停止し、切り替えながら再実行する。

プロセスには、タイムスライスと呼ばれる「とても小さな時間」が与えられ、 Linuxカーネルはスケジューラによってこれを次々に切り替える。 これをコンテキスト切り替えと呼ぶ。

主なスケジューリングアルゴリズムに、ラウンドロビン、協調的スケジューラ、多段フィードバックキューなどがある。Linux 2.6.23以降ではCFSという新しいスケジューラが使われている。

プロセスには、「実行中」「実行可能」「待ち状態」の3つの状態があり、それぞれに切り替わる。待ち状態とは、たとえばfind . | grep hogeでfindの実行終了を待っているgrepのような状態。この間grepの実行はブロックされる。

仮想アドレス空間とページ

カーネルは、実行するプロセスに、テキスト領域(プログラムが格納される)、スタック領域、ヒープ領域などを与える。

カーネルはプログラムがメモリ領域にアクセスした段階で、 論理アドレスを物理アドレスに翻訳する。

これを仮想アドレス空間と呼ぶ。

ハードウェアのMMUという機構を使ってこれを実現している。

このようにすることで、CPUとメモリの組がひとつしかなくても、 プログラムの数だけあるかのように仮想化することができる。

カーネルは三段階のメモリアドレッシングを行う。

すなわち、ページグローバルディレクトリ、ページミドルディレクトリ、ページテーブルである。

もともとは二段階だったが、64bit化された結果二段階では不十分ということになり、 Alphaプロセッサを参考に三段階のアドレッシングがされるようになった。

カーネルは、ページングやセグメンテーションによってメモリ空間を小さく分割して管理している。

C言語のプログラムをコンパイルすると、ネイティブに実行できるバイナリファイルが出来るが、 このプログラムを実行すると、カーネルがこのプロセスがきちんと動くようにメモリ領域を割り当てて管理する。

カーネルは、できるだけ連続したメモリ領域を確保し、空き領域の断片化が起きないように、ページの置換のために頻繁に使用されていない空き領域を選ぶページ置換アルゴリズムや、2を基底する数で管理するバディシステムのような仕組みを使って努力している。

メモリを動的に確保するにはmalloc(), realloc(), calloc()などのAPIを使う。またbrk()やsbrk()も使うが、malloc()系列のAPIとbrk()系列のAPIを同時に使うことはできない。これはmalloc()がbrk()などとともに使われないことを前提として実装されているため。

malloc()した領域は必ずfree()してプログラムの中で解放しなければならない。C言語ではJavaのようなガーベッジコレクションの仕組みがないため、解放しなければメモリリークが起きる。

C++ではnewとdeleteを使ってオブジェクト指向のオブジェクトをmalloc()やfree()と同様に動的スコープで管理できる。この際には構造体のポインタと同じように.の代わりに->を用い、型宣言に*をつける。また、C++でもスマートポインタを用いれば、Javaと同じように自動的に解放されるメモリ領域を管理できる。

また、メモリではないが、プログラムを書く時はエラーチェックをきちんとすること。malloc()のエラーチェックをしなかった場合、システムに存在するメモリが使い果たされた時などの対応ができない。C言語には例外の仕組みがないため、エラーチェックは返り値を条件式で比較してチェックする。

割り込み

カーネルは、IOデバイスの応答を待機している間、別の仕事をする。

IOデバイスが処理を完了して応答した時点で、 デバイスがカーネルに割り込み、処理を継続する。

割り込みとは、このようにカーネルの処理に対してさまざまな場面で割り込んでくる処理のことで、 場合によって例外と呼ばれることもある。

ソフトウェア割り込みとかハードウェア割り込みと区別されることもある。

プロセスとスレッド

プロセスは、それぞれに独立したメモリ領域を用意する。

これに対して、スレッドはプロセスの中に軽量な並列処理を実行し、 メモリ領域を共有する。

スレッドにおいては、競り合い状態が発生しないように、 変数を排他制御(ロック)する必要がある。

プロセスにおいても、プロセス間通信の仕組みを使うことで、 異なるプロセスでデータを共有できる。

セマフォを使うことで、排他制御ができる。 セマフォは、同時に使える人数のうち、あとどれくらいの人数が使えるかを示す整数値を提供する。

プロセス関連のシステムコール・APIとして、fork(), exec(), wait(), exit()などがある。forkをするとその時点からプログラムが二つに分岐する。execをすると自分のプロセスを上書きしてそのプログラムを実行する。特にサーバーなどでは面倒くさくてもforkしよう。

デーモンを作る場合、fork()した上でsetsid()で制御端末を切り離せばよい。

デバイスドライバ

デバイスドライバは、カーネルの中で唯一デバイスコントローラの詳細な仕様を知っている部分。

キャラクタ型デバイスとブロック型デバイスがある。

キャラクタ型デバイスは、ランダムアクセス(好きな時に好きな場所にアクセス)することができない。

ブロック型デバイスは、ランダムアクセスができる。多くの場合、ハードウェアなどのストレージはブロック型デバイスであり、マウントして利用する。

ファイルシステム

カーネルはVFSという機構を使うことで、ファイルシステムが違ってもプログラムを修正する必要はなく、 同じシステムコールからアクセスできる。

ext2やext4はブロック型ファイルシステムで、ブロックでデータを管理し、i-nodeと呼ばれるインデックスからブロック内のデータにアクセスする。

カーネルは、低速なディスクに頻繁にアクセスしないように、ストレージの内容を内部でキャッシュしている。ファイルの書き込みはまずキャッシュに書かれてからその後にディスクに書かれる。なんらかの理由でキャッシュからディスクに書きたいならsyncコマンドを実行する。

i-nodeはデータへとアクセスするためのインデックスのことで、「未使用」「使用中」「ダーティ」に分けられる。ダーティとは「書き込み中」の意味。ダーティフラグがつけられると、カーネルはそれをダーティリストに加えて、I/Oリクエストキューに加え、順次それが書き込まれる。

ext2などのブロック型ファイルシステムは、ブロックの集合であるブロックグループの集合としてデータを保管し、メタデータをスーパーブロックに格納する。

これに対してReiserFSやXFSはデータベースで用いられるB-Treeと呼ばれるインデックスを用いる。

BtrFSのようなコピーオンライトのファイルシステムでは、ファイルはコピーだけされても実際のデータは複製されず、読み取り専用となっている元のファイルの部分を参照する。実際にこのデータに書かれた時にその部分だけが複製される(コピーオンライト)。

このためBtrFSではファイル容量が大幅に削減できるため、過去のその時読まれたデータを残しておくスナップショットの機能を持たせても構わないぐらいの現実的な余裕がある。そのため、障害復旧に優れている。

ネットワーク

カーネルはBSDソケットインターフェースを提供する。

これは互いに関連づけられると有効になり、片方から書き込むと片方から読み込める。

TCPでは再送制御など信頼性確保のための多くの機能があるが、UDPは機能がない代わり、ビデオや音声などを多少誤りがあっても高速に通信できる。

APIは、socket(), bind(), listen(), accept(), connect()となる。サーバ側で待ち受けて待機しているソケットに、クライアントが接続することで、ソケットの連携が可能となる。

カーネル内部では、BSDソケット層とINETソケット層がある。OSI参照モデルでは、ヘッダを付加して上層から下層へとデータを送り、ヘッダを除去して下層から上層へとデータを受け取る。Linuxでは、ソケットバッファsk_buffのポインタをOSI参照モデルの各層に渡していくことでこれを実現している。

シグナル

シグナルはプログラムを強制終了するのに使う。

デフォルトの動作は強制終了やコアダンプなどに限られているが、プロセスの側でシグナルを捕捉(トラップ)し、別の動作をさせることができる。

シグナルはシステムコールsignal()で捕捉できるが、古いので新しいプログラムではsigaction()を使う。

システムコールと入出力

システムコールは、基本的にopen(), close(), write(), read()で行う。

しかしながら、バッファリングを行うstdioのライブラリ関数を使った方が高速。この場合、fopen(), fclose(), fwrite(), fread()などが使えるほか、ほかにもたくさんのAPI関数がある。

システムコールは固定長の読み書きしかできないが、stdioは文字単位や行単位で入出力でき、フォーマット出力などの便利な機能がある。一文字だけ出力するにはputchar()、一文字だけ入力するにはgetchar()を使う。この二つの関数だけでもいろんなプログラムが書ける。

システムコールを使う場合、ファイルディスクリプタと呼ばれる整数値をストリームの識別に用いる。プロセスには、標準入力、標準出力、標準エラー出力のファイルディスクリプタが与えられるが、ファイルやソケットをオープンした場合にもファイルディスクリプタが与えられ、これに対してread()やwrite()することでストリームの読み書きが可能となる。

stdioでは、ファイルディスクリプタをFILEポインタというラッパーに格納する。FILEポインタにはバッファリングの情報や、ファイルのどの位置を今読んでいるかの情報などが格納されている。

単に入出力をするだけなら、fgets()やfputs()、あるいはprintf()などを使う。ファイルに書き込む時はfprintf()を、出力せずに文字列をフォーマットだけしたい場合はsprintf()を使う。また、テキスト処理をする場合、トークン解析などの理由で一文字だけ元に戻したいことがある。この時はungetc()を使う。

カーネルモジュールのロード

insmodで、カレントディレクトリにあるカーネルモジュールをロードできる。

insmod hello.ko

ロードされたモジュールはlsmodで確認できる。

モジュールをアンロードするにはrmmodを行う。

rmmod hello

また、「/lib/modules/`uname -r`」からドライバをロードするにはmodprobeコマンドを使う。

カーネルモジュールのロードの設定は、/etc/modules-load.d/*.confに記述する。オプションは、/etc/modprobe.d/*.confに記述する。

共有ライブラリ

バイナリの依存している共有ライブラリの情報を見たい

lddコマンドでいける。

ldd /bin/ls

lddコマンドは、バイナリが依存する共有ライブラリを表示するコマンド。これに対してldconfigは共有ライブラリのキャッシュを更新するコマンド。共有ライブラリの設定を変えた時はldconfigを実行する。

静的リンクのライブラリは、ビルド時にプログラムに物理的に結合される。動的リンクでは、別々のオブジェクトが作られ、実行時に動的リンクローダが結合する。基本的に、動的リンクを用いるのが一般的。

システムコールをトレースしたい

straceコマンドでいける。

gccとmake

gccの主なコマンド

基本は、

gcc -o test test.c

主なオプションは、

  • -g : デバッグ情報を付加
  • -lm : libmをリンク
  • -O0 : 最適化を無効化
  • -O2 : デフォルトの最適化
  • -O3 : より強固な最適化
  • -E : プリプロセスまでを実行
  • -S : アセンブリ言語までを出力
  • -c : オブジェクトファイルまでを出力
  • -Wall : 警告オプションをすべて有効
  • -g3 : デバッグ情報の付加に加え、gdbでマクロも有効になる
  • -L : ライブラリを参照する場所を指定
  • -I : インクルードヘッダを参照する場所を指定

コンパイラは、字句解析と構文解析からパースツリー(トークンを葉とする構文の構造を表した木構造)を作り、最適化してアセンブリ言語コードを出力する。中間言語表現として3番地コード(3つの番地だけのコードに直す)が知られる。字句・構文解析にはyaccとlexを用いる場合が多い。新しい言語を作りたいのなら、RustのようにLLVMのバックエンドを用いてもいいだろう。

make

Makefileは

作成されるファイル : 依存ファイル
	作成方法

と書く。 たとえば、

test : main.o test1.o test2.o
	gcc -o test main.o test1.o test2.o

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

test1.o : test1.c
	gcc -c test1.c

test2.o : test2.c
	gcc -c test2.c

とすれば、main.cが変更されると以下だけを実行する。

gcc -c main.c
gcc -o test main.o test1.o test2.o

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2021年12月21日 16:18

*1 仮想コンソールや GNU Screen を使えば X でなくても同じことは可能。

*2 または PATH にそのディレクトリを加えることでも対応できる。こうする場合は export PATH=$PATH:/home/huga と実行する。常に設定しておく場合は .bashrc とかの初期化スクリプトに書いておけばOK。

*3 ./ とつける必要があるのは意図しないファイルが実行されるのを防ぐため。((たとえば ls という名前の実行ファイルがあったとして、ls コマンドで中身を見ようとしたときにそれが実行されると困る。こういうときは ./ls と打ち込めばOK))