【UNIX まめ知識】
UNIXに関するメモを気づいた時点で随時メモしておく私的なものです。
◇ ffmpegに付属のffserverを使ってRTSPストリーム配信サーバーを作る
Linuxサーバを192.168.1.203とする。
①ffmpegのインストール
> yum -y install epel-release
> rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
> rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-1.el7.nux.noarch.rpm
> yum -y install ffmpeg ffmpeg-devel
②ffserver用設定ファイルの作成
> vi /etc/ffserver.conf
HttpPort 8090
RtspPort 5554
HttpBindAddress 0.0.0.0
MaxClients 1000
MaxBandwidth 10000
NoDaemon
<Feed feed1.ffm>
File /RTSP/feed1.ffm
FileMaxSize 5M
</Feed>
<Stream stream1.mpeg4>
Feed feed1.ffm
Format rtp
VideoCodec mpeg4
VideoFrameRate 30
VideoBufferSize 80000
VideoBitRate 2000
VideoQMin 1
VideoQMax 5
VideoSize 1920x1080
PreRoll 0
Noaudio
</Stream>
③公開用ファイルを配置
/RTSP/sample.mp4
④ffserverの起動
> ffserver -d
⑤ffserverに公開用ファイルを食わすffmpegも起動(ループ再生)
> ffmpeg -re -f lavfi -i "movie=/RTSP/sample.mp4:loop=0, setpts=N/(FRAME_RATE*TB)" http://192.168.1.203:8090/feed1.ffm
⑥動作確認
VLCの「メディア」→「ネットワークストリームを開く」→「ネットワーク」に以下を入れて「再生」を押下。
表示されればOK。
rtsp://192.168.1.203:5554/stream1.mpeg4
◇ WindowsPCにVMWareを入れ、それ上にLinux(CentOS)を入れて動かす
長いので別ページにまとめました→WindowsPCにVMWareを入れ、それ上にCentOSを入れて動かす
◇ 無料のVMWare playerでも複数環境動かす
アイコンをただ複数回ダブルクリックして複数個起動するだけ
◇ wiresharkで開ける形でtcpdumpでキャプチャ採取する(その後ffftpでバイナリ転送)
>tcpdump –s 0 –x –i end33 tcp port 30111 or tcp port 30112 –w tcpdump_201810041127.cap
◇ C言語:可変引数の関数を可変引数の関数でラップしたい
可変引数の関数 print_original があったとします。
print_original をいじらず、
更に可変引数の関数でラップして提供したい場合。
#include
#include
/* もともとあった可変引数の関数 */
/* この関数はもう直接提供するのを辞めたい */
void print_original(const char* format, ...)
{
printf("print_original :");
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
/* ラップ関数に追加でやらせたい処理 */
void func_add1()
{
printf("func_add1 : called.\n");
}
void func_add2(const char* format, ...)
{
printf("func_add2 :");
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
/* ラップ関数の定義 */
/* 今後は print_original に func_add1 と func_add2 を追加して */
/* print_new として利用者に提供する。 */
#define print_new(fmt, ...) print_original(fmt, __VA_ARGS__); func_add1(); func_add2(fmt, __VA_ARGS__)
/* 利用者 */
void main(void)
{
print_new("[%d %d %d]\n", 10, 11, 12);
}
【実行結果】
print_original :[10 11 12]
func_add1 : called.
func_add2 :[10 11 12]
◇ C言語:汎用ダンプ機能を実装する場合の注意
だいたいがprintf形式の可変パラメタ方式を使うと思うがその際、ダンプ対象データ中に「%」
という文字0x25が混入している場合も考えておくほうが良い。
バイナリデータと同じく「.」なりに置き換え表示対象としたほうが無難。
◇ あるディレクトリ以下のファイルを全てフルパスで表示する。
>find / -exec ls -ld {} \;
応用:find UNIX -exec ls -ld {} \; | awk '{printf("echo %s\ngrep CTL_SID %s\n",$9,$9);}' > t
◇ LMにリンクされているモジュールの一覧をリストアップする
nm -g LM名
◇ C言語:ディレクトリ以下にあるファイルの一覧を得る
#include
DIR* dirp;
struct dirent* direntp;
dirp = opendir("./");
if (NULL == dirp)
{
return ATCL_ERROR;
}
rewinddir(dirp);
while(1)
{
direntp = readdir(dirp);
if (NULL == direntp)
{
break;
}
printf("[%s]\n",direntp->d_name);
}
errno=0;
if (-1 == closedir(dirp))
{
return ATCL_ERROR;
}
====ソートしたかったらこっち↓====
(カレントのmylog_xxxx.xxxという名前のファイルを最新5ファイル残して削除してる例)
#include
int selector(const struct dirent* entry)
{
if (0 == strncmp(entry->d_name,"mylog_",6))
{
return 1;
}
return 0;
}
int i;
int num_entries;
struct dirent **namelist, **list;
num_entries = scandir("./", &namelist, selector, alphasort);
if (num_entries < 0)
{
return ATCL_ERROR;
}
if (0 != num_entries)
{
for (i=0,list=namelist; id_name);
}
free(*list);
list++;
}
}
free(namelist);
◇ C言語:ポインタをprintfする時は%pで!
とにかく%pで!今まで%x使ってたよ!
◇ C言語:特定の漢字コードでコンパイルエラーが出る。
HP-UX, aCC, SJIS 環境で、EUCからSJISに変換したソースをコンパイルしたら
特定の漢字コード内にエスケープ文字(\)が含まれるらしくてエラーになった。
line 1376: warning#2192-D: unrecognized character escape sequence
「-Y」オプションで解決!
◇ C言語:NULL無しでもprintfできる
printf("%.*s\n",NULL無しバッファから出力したいサイズ,NULL無しバッファのポインタ);
◇ 印刷
>lpr -P プリンタ名 印刷したいファイル名;
プリンタ名は/etc/printcapファイルに書いてある。
ちなみにWindowsでプリンタを検索するには
>net view \\ホスト名orIPアドレス
◇ TCP/IPの通信ログの収集
①nettl -c 6 -tn pduin pduout -e ns_ls_ip -s 1024 -tm 1000 -f /tmp/trace1
※-c 6 :データを採取するNICの指定です。環境に合わせて読み替えて
下さい。NICがlan3であれば-c 3と指定。
※-tn pduin pduout:LANインタフェース経由で送受信したパケットの内容を記録
します。
※-e ns_ls_ip:IPパケットの通信を記録する。
※-s 1024:トレースを記録する際のメッセージバッファサイズ(単位:KB)
※-tm 1000:トレース記録用のファイルサイズ指定(単位:KB)
※-f /tmp/trace1:トレース記録用のファイル名
②以下のコマンドを入力しトレースを終了させます。
nettl -tf -e all
◇ デバイス名の命名規則
/dev/[r]dsk/c①t②d③s④
① コントローラナンバー コントローラの数だけある
② バスターゲットナンバー SCSIコントローラの場合なら、装置の背面のスイッチで設定されるSCCI IDのこと
③ ドライブナンバー ターゲットにつけられたドライブの数
④ スライスナンバー 0から7までの値を取る。全ディスクを指定するにはスライス2を指定。
0 / (root)
1 swap
2 全ファイルシステム
6 /usr
ルートファイルシステムでは慣習的に次の様なスライスを使う。
「スライス」=「パーティション」
◇ Xウィンドウのハードコピーを取る
>sleep 5; xwd -fname > xxx.xwd xwd形式でファイルへ保存
>xwdtoppm xxx.xwd | ppmtogif > xxx.gif gif形式に変換
◇ ktermでCtrl+Dを押しても終了しちゃわなくする
>set ignoreeof
もしくは
>stty eof undef
◇ ターミナルが固まっちゃった時の対処
>reset(リターン打たずに)Ctrl+J
printfなんかでターミナルに出力した時に文字化け&
固まっちゃうことがある。そんな時は上記の方法で
ターミナルを初期化すると直る。
◇ あるディレクトリ以下のサイズを知りたい
du -s ディレクトリ名
この結果はブロック数(512byte)で表示されるので
512倍した値がバイト数
◇ C言語:文字列のスペース埋めなどについて(printf,sprintf等)
(注1 右側はスペースサプレスしかできない)
(注2 文字列は例えば「%10.4s」の「.4]の様に最大文字数が指定できるのでオーバフローを気にしなくて良いが
数値は「%10d」とやってもその数値が15桁あったとしたら15桁になってしまうので注意)
文字列 ○ 10桁エリアに文字列を最大4文字まで右詰めして左側をスペースサプレスして表示
コード:printf("[%+ 10.4s]","12345");
結果 :[ 1234]
文字列 ○ 10桁エリアに文字列を最大4文字まで右詰めして左側をゼロサプレスしてして表示
コード:printf("[%+010.4s]","12345");
結果 :[0000001234]
文字列 ○ 10桁エリアに文字列を最大4文字まで左詰めして表示
コード:printf("[%-10.4s]","12345");
結果 :[1234 ]
数値 ○ 10桁エリアに数値を左詰めして表示
コード:printf("[%-10d]",12345);
結果 :[12345 ]
数値 ○ 10桁エリアに数値を右詰めして左側をゼロサプレスして表示
コード:printf("[%010d]",12345);
結果 :[0000012345]
数値 ○ 10桁エリアに数値を右詰めして左側をスペースサプレスして表示
コード:printf("[% 10d]",12345);
結果 :[ 12345]
文字列 ムダ 10桁エリアに文字列を最大4文字まで左詰めして左側をスペースサプレスして表示
コード:printf("[%- 10.4s]","12345");
結果 :[1234 ]
理由 :「左側をスペースサプレス」は左詰めでは意味無し
文字列 ムダ 10桁エリアに文字列を最大4文字まで左詰めして左側をゼロサプレスして表示
コード:printf("[%-010.4s]","12345");
結果 :[1234 ]
理由 :「左側をゼロサプレス」は左詰めでは意味無し
数値 ムダ 10桁エリアに数値を最大3文字まで左詰めして左側をゼロサプレスして表示
コード:printf("[%-10.3d]",12345);
結果 :[12345 ]
理由 :「最大3文字まで」と「左側をゼロサプレス」は左詰めでは意味無し
数値 × 10桁エリアに数値を左詰めして左側をスペースサプレスして表示
コード:printf("[%- 10d]",12345);
結果 :[ 12345 ]
理由 :「左側をスペースサプレス」は左詰めではおかしくなる
数値 × 10桁エリアに数値を右詰めして表示
コード:printf("[%+10d]",12345);
結果 :[ +12345]
理由 :+による右詰めはおかしくなる。
◇ 一定サイズ以上のファイルを探す
一定サイズ以上のファイルを全てリストアップしたい場合は
find / -size +1234 -print
で「1234ブロック以上のファイルを全て表示する」の意味になる。
find / -size +1234c -print
なら「1234バイト以上のファイルを全て表示する」になる。
◇ awkでファイルの中身を検査
---- a.txt --------
1 PAURO MEXICAN
2 MARIER YANKEE
3 TORU JAP
4 KIMU CHON
-------------------
>awk 'BEGIN{
yflag=0;
cflag=0;
}
{
if(match($0,"YANKEE")!=0)
{
yflag=1;
}
if(match($0,"CHON")!=0)
{
cflag=1;
}
}
END{
if((yflag==1)&&(cflag==1))
{
printf("CALM DOWN,BE COOL!\n");
}
}' a.txt
>CALM DOWN,BE COOL!
◇ Cシェル(csh)
ファイルの有無を検査
if (-e $1.tar) then
endif
◇ Bシェル(sh)
ファイルの有無を検査
if [ ! -f ファイル名 ]
コマンドの戻り値を検査
/usr/sbin/ifconfig $1 0 down 2>/dev/null
cmdsts=$?
if [ cmdsts -eq 0 ]; then
echo 0
else
echo 1
fi
◇ stty ~ ktermでバックスペースが効かない!
目的 |
方法 |
DELキーを効かせる |
stty intr ^\? |
BackSpaceキーを効かせる |
stty erase ^H |
CTRL+Cキーを効かせる |
stty intr ^C |
ちなみに「効かせなくする」には
stty erase ""
とすればOKです。
ところで、CTRL+Cが^CでBackSpaceが^H、DELキーは^\?なんてどうやって調べるのか。
これは、
まず
man ascii
と打つと出てくる表を見ます。これによると、
bs がバックスペース
etx がCTL+C
del がDELキー
だそうです、それぞれ
08
03
7f
になってますね。これを「7ビット扱いで40を足す」そうです。具体的には
08 = 0001000 に 40 = 1000000 を足して 1001000 = 48
03 = 0000011 に 40 = 1000000 を足して 1000011 = 43
7f = 1111111 に 40 = 1000000 を足して 0111111 = 3f
この値でもう一度 man asciiの表を見ると
48 = H
43 = C
3f = ?
になってますね。^の意味はわかんないけどとにかく付けましょう(笑)。
\の意味もわかんないけどとにかく付けましょう(謝)。
◇ ログアウトするとSIGHUPが送られてしまう。
例えばコマンドインタプリタdlpshを作ったとして、ログインと同時に起動させる
ために.loginの末尾に
exec dlpsh
と書くとdlpsh終了と共にログアウトする様にできます。
このdlpshから
system("test.csh");
----- test.csh ------------
#!/usr/bin/csh
CSCS &
---------------------------
などとしてプロセスCSCSを起動したとしても、dlpshを終了させると
同時にSIGHUPがプロセスCSCSに投げられてしまいます。
これへの対策の1つとして、CSCSのmainの頭でsetsid()を実行しCSCS
をグループリーダにしてしまう方法があります。
これでdlpshとは別グループなのでSIGHUPも送られません。
他の方法としてtest.cshを
nohup CSCS &
とやればよさそうな事もマニュアルに書かれていたがなぜかダメでした。
◇ シグナル(signal)
シグナル名(番号) |
発生タイミング(killコマンドによる送信は除く) |
SIGHUP(1) |
2台のマシン間でソケット通信をしていて
ソケットをselectやreadで見張っている時に
他方マシンのLANケーブルを抜いて暫くした後に出た。
自マシン側のLANケーブルを抜いた場合はすぐreadがr=0で戻るので気付く。 |
SIGINT(2) |
CTRL+Cを押下した時、フォアグラウンドで動いているプロセスに送られた。 |
SIGBUS(10) |
FD_ISSETマクロの第1引数に-1を与えた時
read/writeなどの引数fdに-1を与えた時
要は既にクローズしてしまったファイルやストリームにアクセスしようとした時 |
SIGALRM(14) |
自分でalarmシステムコールを実施した時 |
SIGTSTP(24) |
CTRL+Zを押下した時、フォアグラウンドで動いているプロセスに送られた。 |
・シグナルについてはハンドラが張れるものは全て張る。ただしハンドラ内ではエラーログの出力
以外何もしない。プログラムが「エラー処理」の項で後述する1処理1結果判定でキチっと作って
あればそちらでエラー判断が完全にできるので、ハンドラ内で関数を呼び出したりはしない。これ
やると後で解析できない。
◇ C言語:rootに変身
以下の様なLMを作り、
============= t.c ==============
#include
int main()
{
setuid(0);
}
================================
>cc -o t t.c
>chown root:sys t
>chmod 4755 t
とすると、このLMは実行すると勝手にrootに変身(setuid実行時点から)して実行される。
但し環境はこのLMを実行するユーザの環境(.cshrcみたいな)が用いられる。
◇ C言語:エラー処理
・void関数を作らない
・1処理1結果判定。エラー時はエラーログを出力してその場でリターン。
・戻り値体系を整える(正常=0、異常=-1、エラー詳細はerrnoに設定する等)
・ログファイルにログを記録する。
・ログファイルはサイクリックファイルとなるしくみを作る。
・エラーログ以外(入出力ログ、デバッグ用ログ)は抑制するモードを用意する。
・1ファイル1関数。ログにはミリ秒時刻、エラー内容、ファイル名、行番号、エラー詳細等を出力。
・シグナルについてはハンドラが張れるものは全て張る。ただしハンドラ内ではエラーログの出力
以外何もしない。プログラムが1処理1結果判定でキチっと作ってあればそちらでエラー
判断が完全にできるので、ハンドラ内で関数を呼び出したりはしない。これやると後で解析できな
い。
関連して、
・グローバル使用の禁止。というかグローバル変数はあってもいいけど必ず引数で渡す。
変数、関数の命名規則すら整っていない場合コードが読みにくくなる。
============ a.c ==============
int main()
{
r = b("/var/tmp/","test.tmp");
if( r == -1 )
{
snprintf(wbuf,sizeof(wbuf),"b FAILED:%s:%s:%s:%d",dir,file,__FILE__,__LINE__);
log(wbuf,ERROR);
}
}
===============================
============ b.c ==============
int b(char *dir,char *file)
{
char path[2048];
strncpy(path,dir,sizeof(path));
strncat(path,file,sizeof(path));
r = c(path);
if( r == -1 )
{
snprintf(wbuf,sizeof(wbuf),"c FAILED:%s:%s:%d",path,__FILE__,__LINE__);
log(wbuf,ERROR);
}
}
===============================
============ c.c ==============
int c(char *filename)
{
errno=0;
r = open(filename,O_CREAT|O_TRUNC|O_RDWR);
if( r == -1 )
{
snprintf(wbuf,sizeof(wbuf),"open FAILED:%d:%s:%s:%s:%d",errno,strerror(errno),filename,__FILE__,__LINE__);
log(wbuf,ERROR);
}
}
===============================
~~~~~~~ログ~~~~~~~
:
12:05:34.20 ERROR:open FAILED:5:Permission Denied:/var/tmp/test.tmp:c.c:7
12:05:34.22 ERROR:c FAILED:/var/tmp/test.tmp:b.c:10
12:05:34.30 ERROR:b FAILED:/var/tmp/:test.tmp:a.c:6
:
~~~~~~~~~~~~~~~~
◇ C言語:ソケット(socket)/サーバ・クライアントモデル
注:「ソースを表示」してカット&ペーストして下さい。
============ server.c ==============
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
int r;
int sock_parent,sock_child,sock_tmp;
struct sockaddr_in server;
char wbuf[256];
int optval=1;
fd_set set_mask;
/*========================================================================*/
/* ソケット生成 */
/*========================================================================*/
errno = 0;
sock_parent = socket(PF_INET,SOCK_STREAM,0);
if( sock_parent == -1 )
{ /* エラーの場合 */
printf("socket FAILED :%d:%s:%s:%d\n",errno,strerror(errno),__FILE__,__LINE__);
exit(-1);
}
/*========================================================================*/
/* ソケットオプション(再利用)設定 */
/*========================================================================*/
errno = 0;
r = setsockopt(sock_parent,SOL_SOCKET,SO_REUSEADDR,(char *)&optval,sizeof(optval));
if( r == -1 )
{ /* エラーの場合 */
printf("setsockopt FAILED :%d:%s:%s:%d\n",errno,strerror(errno),__FILE__,__LINE__);
exit(-1);
}
/*========================================================================*/
/* ソケット情報をセット */
/*========================================================================*/
bzero((char *)&server,sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = 5000;
/*========================================================================*/
/* バインドを行う。 */
/*========================================================================*/
errno = 0;
r = bind(sock_parent,(struct sockaddr *)&server,sizeof(struct sockaddr_in));
if( r == -1 )
{ /* エラーの場合 */
printf("bind FAILED :%d:%s:%s:%d\n",errno,strerror(errno),__FILE__,__LINE__);
exit(-1);
}
/*========================================================================*/
/* リスンを行う。 */
/*========================================================================*/
errno = 0;
r = listen(sock_parent,5);
if( r == -1 )
{ /* エラーの場合 */
printf("listen FAILED :%d:%s:%s:%d\n",errno,strerror(errno),__FILE__,__LINE__);
exit(-1);
}
sock_child = -1;
sock_tmp = -1;
do
{ /* 無限ループ */
/*====================================================================*/
/* 入力待ち対象の設定 */
/*====================================================================*/
FD_ZERO( &set_mask );
if( sock_child == -1 )
{ /* accept前 */
FD_SET(sock_parent,&set_mask);
}
else
{ /* accept後 */
FD_SET(sock_child,&set_mask);
}
/*====================================================================*/
/* 入力待ち */
/*====================================================================*/
errno = 0;
r = select(FD_SETSIZE,&set_mask,0,0,NULL);
if( r == -1 )
{ /* エラーの場合 */
if( errno == EAGAIN )
{
continue;
}
else if( errno == EINTR )
{
continue;
}
else
{
printf("select FAILED :%d:%s:%s:%d\n",errno,strerror(errno),__FILE__,__LINE__);
exit(-1);
}
}
/*====================================================================*/
/* 入力別の処理を行う */
/*====================================================================*/
if(sock_parent != -1)
{
if(FD_ISSET(sock_parent,&set_mask))
{ /* 親ソケットへの入力を検出した場合 */
/*============================================================*/
/* ソケットの接続 */
/*============================================================*/
errno=0;
sock_child = accept(sock_parent,NULL,NULL);
if( r == -1 )
{ /* エラーの場合 */
printf("accept FAILED :%d:%s:%s:%d\n",errno,strerror(errno),__FILE__,__LINE__);
exit(-1);
}
sock_tmp = sock_parent;
sock_parent = -1;
}
}
if(sock_child != -1 )
{
if(FD_ISSET(sock_child,&set_mask))
{ /* 子ソケットへの入力を検出した場合 */
r = read(sock_child,wbuf,sizeof(wbuf));
printf("read:%d[%s]\n",r,wbuf);
close(sock_child);
sock_child = -1;
sock_parent = sock_tmp;
}
}
}while(1);
}
====================================
============ client.c ==============
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
int r;
int sock;
struct sockaddr_in server;
char wbuf[256];
int optval=1;
struct hostent *hp;
/*========================================================================*/
/* ソケット生成 */
/*========================================================================*/
errno = 0;
sock = socket(PF_INET,SOCK_STREAM,0);
if( sock == -1 )
{ /* エラーの場合 */
printf("socket FAILED :%d:%s:%s:%d\n",errno,strerror(errno),__FILE__,__LINE__);
exit(-1);
}
/*========================================================================*/
/* ソケットオプション(再利用)設定 */
/*========================================================================*/
errno = 0;
r = setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&optval,sizeof(optval));
if( r == -1 )
{ /* エラーの場合 */
printf("setsockopt FAILED :%d:%s:%s:%d\n",errno,strerror(errno),__FILE__,__LINE__);
exit(-1);
}
/*========================================================================*/
/* ソケット情報をセット */
/*========================================================================*/
bzero((char *)&server,sizeof(server));
hp = gethostbyname("suzaku");
if( hp == NULL )
{ /* エラーの場合 */
printf("gethostbyname FAILED :%d:%s:%s:%d\n",errno,strerror(errno),__FILE__,__LINE__);
exit(-1);
}
memcpy((char *)&server.sin_addr,(char *)hp->h_addr,hp->h_length);
server.sin_family = AF_INET;
server.sin_port = htons(5000);
/*========================================================================*/
/* コネクトを行う。 */
/*========================================================================*/
r = connect(sock,(struct sockaddr *)&server,sizeof(struct sockaddr_in));
if( r == -1 )
{ /* エラーの場合 */
printf("connect FAILED :%d:%s:%s:%d\n",errno,strerror(errno),__FILE__,__LINE__);
exit(-1);
}
strcpy(wbuf,"THIS IS TEST");
r = write(sock,wbuf,strlen(wbuf));
printf("write:%d[%s]\n",r,wbuf);
close(sock);
}
====================================
~~~~~~~コンパイル~~~~~~
>cc -o server server.c -lsocket -lnsl -lgen
>cc -o client client.c -lsocket -lnsl -lgen
~~~~~~~~~~~~~~~~~~
◇ C言語:ミリ秒単位でsleep
nap(20); ・・・ 20ミリ秒sleep
注:システムクロックは一般に10ミリ秒単位なのでそれ以下の指定は切上げられる。
◇ プロセスが何をやっているのかを覗く方法
EWS-UXに関して言えば、
>truss pid
とやればpidのプロセスが今何のシステムコールを呼び出しているかがわかります。
同様に、
OS名 |
コマンド名 |
EWS-UX,UP-UX |
truss |
Solaris |
truss |
Linux |
strace |
SGI |
par,strace |
FreeBSD |
ktrace |
BSDI |
ktrace |
HP-UX |
tusc,trace |
Tru64(Digital) Unix |
trace |
だそうです。
|
|