(Adjust Clock version 0.1.1)
* このプログラムは無償ですが、何の保証もなければ、補償もありません。あなたがこのプログラムを使用して被ったいかなる不利益についても、作者は一切その責を負いません。各自の責任でご利用ください。
adjclockは現在時刻を合わせるために使用します。通常、現在時刻はdateコマンドなどで設定しますが、adjclockは30秒以内の誤差ならば、時刻入力の必要がありません。ただし、設定する時刻は毎分00秒に限ります。本来、adjclockはadjclockdを呼び出すためのインターフェースですが、adjclockdがない場合でも、settimeofdayシステムコールを用いて時刻の修正を行うことができます。
まず、adjclock.txtを表示させて、adjclock.cとしてセーブしてください。Unixマシン上なら改行コードや漢字コードは問題ないと思いますが、ダウンロードをWindowsマシンなどで行う場合はちょっと気にする必要があるかもしれません。まあ、漢字はコメントにしか入ってないので、読めないだけで大きな問題は生じないと思います。(^-^; Linux・FreeBSDとも、普通にccでコンパイルすればバイナリができあがるはずです。特に依存しているカーネルオプションもないはずです。
cc -Wall -o adjcock adjclock.c
Linux 2.0.34(Slackware 3.5 + PJE 0.15cm)、FreeBSD 3.1で動作の確認がなされています。バイナリができあがったら、/usr/local/sbinなどにコピーしてください。
スーパーユーザーになって、とりあえず以下のように打ち込んでください。スーパーユーザーじゃなくても実行はできますが、最後に時刻を合わせるところで「パーミッションがない」と怒られることになっています。
adjclock
すると、以下のように表示されます。
This program adjusts the time. Press [Enter] at TOP OF THE MINUTE.
If you've executed this program at top of the minute,
press [A] and [Enter]. --->
英文にあんまり自信がないのですが、本人としては、「00秒の時報に合わせて[Enter]を押してね」と書いたつもりです (^-^; ので、117に電話するなり、JJYを聞くなり、NHKをつけるなりして、00秒の時報に合わせて[Enter]を押してください。もし、00秒の時報と同時にadjclockを実行してしまった人は、時報はもう気にせずに[A][Enter]と押してあげます([A]は大文字でも小文字でも結構です。以下同様)。すると、
It's 12:12. Isn't it? [Y]/N
と、正しいと思われる時刻を表示してきますので、これでよければ[Enter]を押します。時計が30秒以上狂っていると、ここで表示される時刻は間違ったものになりますので、その時は[N][Enter]と押します。[N][Enter]と入力した場合は、
It's 12:12. Isn't it? [Y]/N N
What minute of the hour? ->
と聞かれますので、何分かを00〜59までで入力してください。先ほどの例で、12:12って表示されたけど、実は時計が20分進んでいて、正しい時刻は11:52だ(爆)という場合は、「52」だけを打ち込みます。すると、
What minute of the hour? -> 52
It's 11:52. Isn't it? [Y]/N
と、また聞いてくるので、これでよければ[Enter]を押してください。時刻が30分以上ずれている場合にはもうどうしようもないので、[CTRL]+[C]で止めて素直にdateコマンドを使ってください。
ここで[Enter]と入力すると、/var/run/adjclockd.pidがあれば、/var/run/adjclockd.cmdが生成されて、adjclockdにSIGHUPが送られます。正常に終了すれば、
It's 11:52. Isn't it? [Y]/N
Kernel clock gains 1202.345678 second.
Sent HUP signal to adjclockd daemon.
と表示されます。syslogの設定にもよりますが、/var/log/messagesあたりを見ると、実際にadjclockdが何をしたかが分かると思います。誤差が50mSec以下の場合には、
It's 12:12. Isn't it? [Y]/N
Kernel clock loses 0.012345 second.
Error is less than 50mSec. Nothing has done.
と表示され、何も行われずに終了します。adjclockdにシグナルを送れなかった場合やadjclockdがそもそもない場合には、
It's 12:12. Isn't it? [Y]/N
Kernel clock loses 0.012345 second.
(adjclockdにシグナルを送れなかった場合はここに理由が表示されます)
Do you want to adjust time by using settimeofday? [Y]/n
とたずねられるので、settimeofdayで時刻合わせをしたいのなら[Enter]を、やっぱりや〜めた、という場合には[N][Enter]を入力してください。入力すると、Done.あるいは Canceled.という表示か、エラーがあった場合にはエラーメッセージが出ます。Done.が出た場合には時刻修正が完了しています。それ以外の場合は時刻は設定されていません。
adjclockdのpidを調べるために使用します。
adjclockdにコマンドを送るために使用します。
各種システムコール・ライブラリ関数の実行に失敗した場合には、perror関数によってエラーメッセージを表示しています。以下では、それ以外のエラーメッセージについて解説します。
EOF or error detected.
EOF detected.
Incorrect character. Aborted.
The value must be 00 to 59. CTRL+C to abort.
/var/run/adjclockd.pid exists, but is incorrect or no such process.
It seems that adjclockd is not running.
- adjclockdにSIGHUPを送ろうとしましたが、adjclockd.pidファイルに書いてあるプロセスIDのプロセスが存在しなかった場合に表示されます。adjclockdが動作しているかどうか、psコマンドなどで確認してください。処理は続行され、settimeofdayで時刻を設定するかどうかたずねられます。
/var/run/adjclockd.pid exists, but no pid in the file.
It seems that the file is corrupted.
- adjclockd.pidファイルは存在していますが、内容がおかしい場合に発生します。かなり希なケースなはずです。処理は続行され、settimeofdayで時刻を設定するかどうかたずねられます。
| 0 | 正常に終了しました。時刻が設定されたかどうかは操作や条件によります。 |
| 1, 4, 11 | gettimeofdayの実行に失敗しました。 |
| 3 | adjclockd.pidファイルのオープンに失敗しました。 |
| 5 | 入力中に規定外の文字が入力されました。 |
| 6, 10 | 入力中にEOF(CTRL+D)が入力されました。 |
| 12 | settimeofdayの実行に失敗しました。 |
| 20 | 時刻の設定がキャンセルされました。 |
閏秒に対応していません。
ここでは知らなくてもいいんだけど、知っているとちょっと便利な話を紹介しておきます。
dateコマンドなんかだと、時分秒を律義に入力しないといけません。まあ、dateなら一秒単位で打ち込めるので、117に電話しながら時間を合わせていて、「う゛、30秒を過ぎちまったぜ」という場合でも、123441とか打って、40秒の時報の次の秒に合わせればいいので、これはこれでロスが少ないのですが、面倒と言えば面倒。
adjclockでは0秒の時報にEnterを押すことで、勝手に時刻を推察してくれます。0秒に丸め込む方法はいろいろあると思いますが、ここではとりあえず、一度localtimeで時分秒に分解しておいて、秒が30秒未満だったら元々のtimeval構造体からその秒数を引き、30秒以上だったら、60−(その秒数)をtimeval構造体に足しています。これでもう一度localtimeで変換すると、めでたく秒は0になっています。面倒な桁上げを考えなくていいのがこの方法の利点。
分に対する丸めも同じような考え方です。分を入力してもらったら、時分秒に分解した方の分との差を求めます。差が30分以上になる場合は、60を足すか、引くかして30分以内に押え込みます。これに60をかけて、元のtimeval構造体から引くと、あら不思議、自動的に近い方の時間に丸め込まれているはずです(なんでこうなるかはよ〜く考えてみて下さい)。
ソースを見るとやたらとgettimeofdayがありますが、実行直後のgettimeofdayは00秒と同時にadjclockを実行しちゃった人用、Enter入力直後のgettimeofdayが普通の人用で、そのあと時刻を確認したら誤差を求め、実際に時刻を設定する前にもう一度gettimeofdayで現在時刻を求め、それに誤差を足してsettimeofdayします。最後のgettimeofdayを怠ると、確認入力する時間が加わってしまい、変な時刻に設定されてしまいます。
adjclockdを使う場合は誤差量だけ分かればいいので、最後のgettimeofdayは実行されません。