Linux/雑記

提供: Wikinote
移動: 案内検索

覚え書き

未分類の覚え書き。

dd コマンドについて

ピンポイント書き込み

例えば、64 バイトのデータの 31-32 バイト目だけを書き換えたい場合。

# od -Ad -tx1 test -v
0000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000016 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000032 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000048 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000064
# echo -n $'\x55'$'\xaa' | dd of=test bs=1 seek=30 conv=notrunc
2+0 records in
2+0 records out
2 bytes (2 B) copied, 3.7856e-05 seconds, 52.8 kB/s
# od -Ad -tx1 test -v
0000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000016 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa
0000032 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000048 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000064

conv=notrunc がないと、書き込みが終わった位置で切り詰められてしまうので要注意。

man コマンドについて

整形幅を指定する

デフォルトでは、ターミナルの幅に整形されてしまうので、横長いターミナルを利用している場合、コピーしてメールなどにそのまま貼り付けるのには適さない。以下の環境変数で、整形幅を指定することができる。

$ MANWIDTH=80 man ...

cpio コマンドについて

よく忘れるのでメモ。man も見にくいし。

  • -i — ファイル抽出
    • -d — 必要に応じてディレクトリを作成
    • -m — ファイルの更新時刻を保持
  • -t — リスト表示
  • -v — verbose
$ rpm2cpio hoge.rpm | cpio -ivdm # 全ファイル抽出
$ rpm2cpio hoge.rpm | cpio -tv # リスト表示 (ls -l)

Makefile について

  • http://www.unixuser.org/~euske/doc/makefile/
  • コマンドの前に '-' をつけると、エラーが発生しても make を続ける
  • コマンドの前に '@' をつけると、コマンドを標準出力に表示しない

initrd を展開する

initrd (イニシャル RAM ディスク) は gzip で圧縮されているようである。

[root@centos52 ~]# file /boot/initrd-2.6.18-164.11.1.el5.img 
/boot/initrd-2.6.18-164.11.1.el5.img: gzip compressed data, from Unix, last modified: Sat Mar 13 13:07:34 2010, max compression

解凍してみると、今度は cpio アーカイブだということがわかる。

[root@centos52 ~]# gzip -cd /boot/initrd-2.6.18-164.11.1.el5.img > initrd
[root@centos52 ~]# file initrd 
initrd: ASCII cpio archive (SVR4 with no CRC)

ということで、こんな感じで展開できる。

[root@centos52 ~]# mkdir tmp && cd tmp
[root@centos52 tmp]# gzip -cd /boot/initrd-2.6.18-164.11.1.el5.img | cpio -idvm

ちなみに、cpio のオプションって面白くて、人によって様々なうえ、同じ人が実行する時は必ず同じオプションなので /root/.bash_history などを見ると誰が実行したのかがわかる。オレが cpio で展開するするときはいつも -idvm を付けるし、 こないだ上司が打っているのを見ていたら、-B とか -u とかも入っていたように見えた。

オプションが複雑だから半分おまじないとして覚えてしまうんだよな。それぞれの意味は忘れちゃってる。

crash の使い方

情けないことだが、ダンプファイルの開き方自体を毎回忘れてしまう。 man crash を見てもパッと見ではわからないのでメモしておく。

# crash /boot/System.map-XXX /usr/lib/debug/lib/modules/XXX/vmlinux vmcore
※XXX は該当するカーネルバージョン

万能ビューア less

ここ 2, 3 年はほぼ毎日 Linux 触ってるのに知らなかった驚愕の事実。

例えば、gzip 圧縮されたファイルがあるとする。

$ echo hoge | gzip -cf > hoge.gz # "hoge" という文字列を圧縮したものを hoge.gz として保存
$ zcat hoge.gz # ふつう、テキストなら zcat とかで内容を確認できる。
hoge

実は、less でもそのまま閲覧可能だ。

$ less hoge.gz
hoge

これは、シェルスクリプト /usr/bin/lesspipe.sh にて実装されている機能である。 スクリプトを確認すると、gz ファイルの他にも、主に以下のものを表示可能だ。

  • man ページ (圧縮されたものを含む)
  • tar ファイル (内容リスト表示; gzip, bzip2 圧縮されたものを含む)
  • zip ファイル (内容リスト表示)
  • rpm パッケージ (パッケージ情報、更新履歴、内容リスト表示)
  • cpio ファイル (内容リスト表示)
  • 各種画像ファイル (画像情報表示)

使用するスクリプトは環境変数 LESSOPEN で指定可能なので、 自分仕様に less をカスタマイズすることもできる。

[hagio@lab ~]$ echo $LESSOPEN
|/usr/bin/lesspipe.sh %s

/proc/diskstats の各項目の意味

Documentation/iostats.txt に書いてあった。

Field  1 -- # of reads completed
    This is the total number of reads completed successfully.
    ★読み込みが成功した回数
Field  2 -- # of reads merged, field 6 -- # of writes merged
    Reads and writes which are adjacent to each other may be merged for
    efficiency.  Thus two 4K reads may become one 8K read before it is
    ultimately handed to the disk, and so it will be counted (and queued)
    as only one I/O.  This field lets you know how often this was done.
    ★読み書きの I/O がそれぞれまとめて行なわれた回数
Field  3 -- # of sectors read
    This is the total number of sectors read successfully.
    ★読み込みに成功したセクタ数
Field  4 -- # of milliseconds spent reading
    This is the total number of milliseconds spent by all reads (as
    measured from __make_request() to end_that_request_last()).
    ★読み込みにかかった時間 (ミリ秒)
Field  5 -- # of writes completed
    This is the total number of writes completed successfully.
    ★書き込みが成功した回数
Field  7 -- # of sectors written
    This is the total number of sectors written successfully.
    ★書き込みに成功したセクタ数
Field  8 -- # of milliseconds spent writing
    This is the total number of milliseconds spent by all writes (as
    measured from __make_request() to end_that_request_last()).
    ★書き込みにかかった時間 (ミリ秒)
Field  9 -- # of I/Os currently in progress
    The only field that should go to zero. Incremented as requests are
    given to appropriate request_queue_t and decremented as they finish.
    ★実行中の I/O リクエスト数
Field 10 -- # of milliseconds spent doing I/Os
    This field is increases so long as field 9 is nonzero.
    ★I/O リクエストが存在した時間?(ミリ秒)
Field 11 -- weighted # of milliseconds spent doing I/Os
    This field is incremented at each I/O start, I/O completion, I/O
    merge, or read of these stats by the number of I/Os in progress
    (field 9) times the number of milliseconds spent doing I/O since the
    last update of this field.  This can provide an easy measure of both
    I/O completion time and the backlog that may be accumulating.
    ★I/O 数 x 経過時間 = I/O のべ時間
      (個々の I/O の待ち時間を含む開始から完了までの時間の総和)

tar で必要なファイルのみを抽出

以下のようなファイルがあるとして、hoge だけを抽出したければ

[hagio@localhost ~]$ tar tzf test.tar.gz 
dir1/
dir1/hoge
dir1/fuga
dir2/
dir2/fuga
[hagio@localhost ~]$ tar xzf test.tar.gz *hoge
[hagio@localhost ~]$ ls
dir1  test.tar.gz

locate 用データベースから除外

locate でファイルを検索する際、updatedb にて作成されたデータベースが用いられる。 テンポラリファイルや、バックアップファイルなどを検索する必要はないので、 これらを除外しておけば無駄がなくなると思われる。

# vi /etc/updatedb.conf
PRUNEFS = "auto afs iso9660 sfs udf"
★PRUNEPATHS = "/afs /media /net /sfs /tmp /udev /var/spool/cups /var/spool/squid /var/tmp"

ここに除外するディレクトリを追加すれば良い。

ビープ音がうるさい

# vi /etc/inputrc
set bell-style none

date コマンドについて

時間を進める/戻す

しょーもないけど覚え書き。ntp の実験なんかで時刻を書き換えたい場合、

# date --set "10 seconds ago"

といった書き方ができる。時刻を進めるには、ago の反対が必要… かと思っていろいろ調べていたが見つからない。

# date --set "10 seconds"

で 10 秒後に進められるじゃん orz

ちなみに、hwclock コマンドも同様のフォーマットが利用可能だ。

# hwclock --set --date "10 sec ago"

UNIX 時間を可読化

わざわざ awk を使って、以下のようにやっていたが、

$ echo 1260750958 | awk '{print strftime("%F %T", $0)}'
2009-12-14 09:35:58

date コマンドでも可能だった!!

$ date -d @1260750958
2009年 12月 14日 月曜日 09:35:58 JST

可読時間を UNIX 時間化

逆変換も可能!!

# date +%s ★現在
1284543415
# date +%s -d 'Sep 15 18:37:10' ★messages 形式 (今年になる)
1284543430
# date +%s -d 'Sep 15 18:37:10 2009' ★messages 形式 (西暦指定)
1253007430
# date +%s -d '2010/09/15 18:37:10' ★日本的形式
1284543430

top について

top の man ページは読みづらいので、あまり読みたくない。

すべてのプロセスの top 情報を表示する

通常は画面に収まるだけのプロセスの情報しか表示されないが、すべてを出力することもできる。

# top -bn 1
-b
バッチモード。テキストに出力する場合はこれを使う。
-n number
出力する回数を指定する。

激速 top

# top -d 0.01
-d ss.tt
出力する間隔を指定する。マニュアルには、小数点以下は 1/10 秒と書いてあるが、1/100 秒までいけるようだ。よって、0.01 が最速で、Celeron 1.80 GHz だと 40 % 程度の CPU 時間を消費する。かるーく負荷をかけたいときなんかには、調節ができて便利。(ぇ

telnet-server について

telnet サーバの立ち上げかたと、ハマったところ。

  1. /etc/xinetd.d/telnet 中の disable = yesno にする
    • chkconfig telnet on でもよい
  2. /etc/init.d/xinetd restart で xinetd を再起動する (これがわからずハマった…)

以下のようなエラーが出て接続できない場合

Trying 192.168.1.1...
Connected to server.
Escape character is '^]'.
getaddrinfo: localhost Name or service not known
Connection closed by foreign host.

/etc/hosts に 192.168.1.1 server.hagio.org を追加するとよい。 ホスト名 "server" だけではダメで、FQDN にしたら接続できた。要するに、hostname コマンドの出力結果を貼付ける。 これも数時間ハマった。なぜこうしないといけないのかは不明なので、そのうち調査する。

ioctl() の使い方

  • 基本的には、fd = open() して ioctl(fd, request, ...) して close(fd) という流れ。
  • request は、man ioctl_list から探す。引き数の型も書いてあるので、これを参考にする。
  • サンプルコード:setro.c - RO (リードオンリー) フラグをセットする
#include <stdio.h>
#include <fcntl.h>
#include <linux/fs.h>

int main(int argc, char* argv[]) {
	int fd, res, flag;

	if (argc != 3) {
		printf("Usage: setro DEVICE RO_FLAG\n");
		return 1;
	}

	if ((fd = open(argv[1], O_RDWR)) < 0) {
		perror("open() failed");
		return 1;
	}

	flag = (int) *argv[2] - '0';
	if ((res = ioctl(fd, BLKROSET, &flag)) < 0) {
		perror("ioctl() failed");
		close(fd);
		return 1;
	}
	close(fd);
	return 0;
}

実行例:/dev/sda1 (/boot) をリードオンリーにする。

[root@centos52 ~]# umount /boot ★いったんアンマウント
[root@centos52 ~]# ./setro /dev/sda1 1 ★リードオンリーにセット
[root@centos52 ~]# mount /boot
mount: ブロックデバイス /dev/sda1 は書き込み禁止です、読込み専用でマウントします
[root@centos52 ~]# umount /boot
[root@centos52 ~]# ./setro /dev/sda1 0 ★リードオンリーを解除
[root@centos52 ~]# mount /boot

/etc/sysconfig/i18n について

  • 読み込まれる場所
    • /etc/rc.d/rc.sysinit (rhgb 利用時のみ?)
    • /etc/init.d/functions/etc/profile.d/lang.sh
    • /etc/init.d/firstboot
  • SUPPORTEDsystem-config-language (GUI アプリ) が使う

その他

リダイレクトの謎

リダイレクトの動きを確認するために、標準出力と標準エラーに文字列を吐くプログラムを書いた。

[hagio@lab ~]$ cat > stdout.c
#include <stdio.h>
int main(void) {
    fprintf(stdout, "stdout\n");
    fprintf(stderr, "stderr\n");
    return 0;
}

これを普通に実行すると、もちろん stdout が先に出力される。

[hagio@lab ~]$ cc -o stdout stdout.c && ./stdout
stdout
stderr

しかし、標準出力と標準エラーを同じファイルにリダイレクトすると…

[hagio@lab ~]$ ./stdout > test 2>&1
[hagio@lab ~]$ cat test 
stderr
stdout

なぜ逆転する?? とりあえず、ltrace を取ってみる。

[hagio@lab ~]$ ltrace -tt -o ltrace.log ./stdout > tmp 2>&1
[hagio@lab ~]$ cat tmp
stderr
stdout
[hagio@lab ~]$ cat ltrace.log 
20:03:34.192236 __libc_start_main(0x80483d4, 1, 0xbf80f644, 0x8048450, 0x8048440 <unfinished ...>
20:03:34.192460 fwrite("stdout\n", 1, 7, 0x5de4c0) = 7
20:03:34.193010 fwrite("stderr\n", 1, 7, 0x5de560) = 7
20:03:34.193327 +++ exited (status 0) +++

ちゃんと "stdout" を書き出す方が先に呼び出されている。しかし、strace を取ってみると…

[hagio@lab ~]$ strace -tt -o strace.log ./stdout > tmp 2>&1
[hagio@lab ~]$ tail -n 4 strace.log
20:05:49.658550 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f62000
20:05:49.658611 write(2, "stderr\n", 7) = 7
20:05:49.658907 write(1, "stdout\n", 7) = 7
20:05:49.658993 exit_group(0)           = ?

うむむむむ、これは何か「エラーは早く表示すべき」みたいなバイアスがかかってるのか…。 glibc が怪しいので、ソースでも見てみるか。

2009/06/30 少し追ってみたが、glibc 全然読めん…。ただ、気になったのはここ

"libio/stdfiles.c"
DEF_STDFILE(_IO_2_1_stdin_, 0, 0, _IO_NO_WRITES);
DEF_STDFILE(_IO_2_1_stdout_, 1, &_IO_2_1_stdin_, _IO_NO_READS);
DEF_STDFILE(_IO_2_1_stderr_, 2, &_IO_2_1_stdout_, _IO_NO_READS+_IO_UNBUFFERED);★

_IO_UNBUFFERED というフラグが立っているようだ。 なるほど、通常 fwrite() で使われるバッファを経由しないから、順番が入れ替わっちゃうわけね。おもろい。