Updated: 2017-09-09
サンプルコードのtail.cを参照してください。
このコードではリングバッファ(ring buffer)というデータ構造を使っています。 リングバッファは実体としては固定長のバッファなのですが、 末尾まで到達したら最初に戻ってデータを上書きするところが異なります。
tailコマンドの場合、ファイルを読み込みながら常にそのときの末尾10行だけがあれば十分なわけです。 言い換えると、11行目を読んだら1行目は不要になるはずです。 そこで11行目は1行目を書いたところに上書きしてしまえばいいだろうという発想が出てきます。 リングバッファはまさにそのような処理をするためのデータ構造です。
サンプルコードのmkpath.cを参照してください。
このmkpath.cでは、まずmkdir(2)を実行してみて、 エラーになったら親ディレクトリを作りに行くという戦術を採用しています。 例えば mkpath a/b/c を実行したときは、まず a/b/c をmkdirしてみて、成功したらそれで終わります。 mkdirがENOENTで失敗した場合は a/b が存在しないと思われるので、make_path関数を再起呼び出しして a/b を作ります。 この繰り返しでディレクトリを再帰的に作成します。
この戦術のよいところは、同じ戦術のmkpathプログラムがいくつ同時に動いていても正常に動作するところです。 例えば他の方法としてはstat(2)でディレクトリが存在するかチェックしてからmkdir(2)で作りに行く方法も考えられます。 しかし、その方法だと、stat(2)でチェックした直後に他のプロセスがディレクトリを作ってしまい、 mkdir(2)がエラーになる可能性があります。 まずmkdir(2)する戦術だと、そのような微妙なタイミングによるエラーは起きません。
サンプルコードのtrap.cを参照してください。
メッセージを出力してexitするだけの関数をsigaction(2)でSIGINTのハンドラーとして登録しておき、 pause(2)でシグナルをじっと待ちます。特に難しいところはないですね。
サンプルコードのls2.cを参照してください。
stat(2)を使ってファイルのオーナーのユーザーIDと最終更新時刻(time_t)を取得し、 ユーザーIDはgetpwuid(3)で名前に、時刻はctime(3)で文字列に変換します。 そこは難しくないと思いますが、パスのバッファを確保するのが地味に面倒ですね……。
「telnet ホスト名 サービス名(またはポート番号)」で任意のサーバに接続できるので、 localhostのdaytimeサーバに接続するなら「telnet localhost daytime」で接続します。 すると次のように現在時刻が表示され、自動的に接続が切れるはずです。
Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 10 SEP 2017 20:57:56 JST Connection closed by foreign host.
サンプルコードのechoclient.cを参照してください。
内容はほとんどdaytimeクライアントと同じです。 ややハマりがちな点は、fdopenするときにモードを書き込み可能(w+)にするのを忘れる、くらいでしょう。