2013年12月2日月曜日

[webGL] DEM データビュワー by webGL

地理情報プロファイル Ver.2.XでフォーマットされたDEMデータのビュワーを作ってみた。
というか手段(webGL)が完璧に目的化しているけど。。。

とりあえず形には、なったので公開。

本当は、file apiでクライアント側のテキスチャ画像を選択できる様にしたかったが、サーバー上の画像ファイルしか貼れないのがthree.jsの仕様らしく断念。

いや違うまたは、別の方法があればどなたか教えてください。


2013年11月9日土曜日

2013年10月22日火曜日

[c] (広義の)コンパイルの工程

分かっていなかった事が分かったので
コンパイルの工程を復習するために hello.cに依存しているtest.cのコンパイル過程を
FreeBSD 9.1 RELEASE で出力してみた。

-hello.h-
#ifndef HELLO_H
#define HELLO_H

int sayHello(void);

#endif

-hello.c-
#include "stdio.h"
#include "hello.h"

int
sayHello(void)
{
  printf("hello\n");
  return 0;
}

-test.c-
#include <stdio.h>
#include "hello.h"

int
main(int argc, char **argv)
{
  sayHello();
  return 0;
}


なお、あらかじめhello.cは中間ファイル(オブジェクトコード)hello.oを生成済み。

$ gcc -o test -save-temps -v hello.o test.c

-save-temps … 通常は、削除される中間ファイルをカレントディレクトリに残す
-v … 途中コマンドを標準エラー出力にコマンドのバージョン情報も含めて出力する

以下が出力したコマンド

Using built-in specs.
Target: amd64-undermydesk-freebsd
Configured with: FreeBSD/amd64 system compiler
Thread model: posix
gcc version 4.2.1 20070831 patched [FreeBSD]
 /usr/libexec/cc1 -E -quiet -v -D_LONGLONG test.c -fpch-preprocess -o test.i #1
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/gcc/4.2
 /usr/include
End of search list.
 /usr/libexec/cc1 -fpreprocessed test.i -quiet -dumpbase test.c -auxbase test -version -o test.s #2
GNU C version 4.2.1 20070831 patched [FreeBSD] (amd64-undermydesk-freebsd)
compiled by GNU C version 4.2.1 20070831 patched [FreeBSD].
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: a8daf30220ba0c32c21af96787b683e6
 /usr/bin/as -V -Qy -o test.o test.s #3
GNU assembler version 2.17.50 [FreeBSD] 2007-07-03 (x86_64-unknown-freebsd) using BFD version 2.17.50 [FreeBSD] 2007-07-03
 /usr/bin/ld --eh-frame-hdr -V -dynamic-linker /libexec/ld-elf.so.1 -o test /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/lib -L/usr/lib hello.o test.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/crtend.o /usr/lib/crtn.o #4
GNU ld 2.17.50 [FreeBSD] 2007-07-03
  Supported emulations:
   elf_x86_64_fbsd
   elf_i386_fbsd


#1 プリプロセス
cc1 がコンパイラ本体らしい
以下が出力されたtest.i の一部
マクロ展開とインクルードファイルの中身の出力が行われていることが確認できる。

# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 39 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 40 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/sys/_null.h" 1 3 4
# 41 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/sys/_types.h" 1 3 4
# 33 "/usr/include/sys/_types.h" 3 4
# 1 "/usr/include/machine/_types.h" 1 3 4
# 51 "/usr/include/machine/_types.h" 3 4
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef short __int16_t;
typedef unsigned short __uint16_t;
typedef int __int32_t;

=中略=

# 2 "test.c" 2
# 1 "hello.h" 1



int sayHello(void);
# 3 "test.c" 2

int
main(int argc, char **argv)
{
  sayHello();
  return 0;
}

#2 アセンブリコード生成


-test.s-
.file "test.c"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB3:
pushq %rbp
.LCFI0:
movq %rsp, %rbp
.LCFI1:
subq $16, %rsp
.LCFI2:
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
call sayHello
movl $0, %eax
leave
ret
.LFE3:
.size main, .-main
.section .eh_frame,"a",@progbits
.Lframe1:
.long .LECIE1-.LSCIE1
.LSCIE1:
.long 0x0
.byte 0x1
.string "zR"
.uleb128 0x1
.sleb128 -8
.byte 0x10
.uleb128 0x1
.byte 0x3
.byte 0xc
.uleb128 0x7
.uleb128 0x8
=以下略=


#3 アセンブル
アセンブルのコードを機械語に変換 オブジェクトファイル(*.o)を出力する


#4 リンク
必要なライブラリをリンクして、最終的な実行形式ファイル(ELF)を出力する。
以下は、出力されたバイナリに依存する共有ライブラリを表示

$ ldd test

test:
libc.so.7 => /lib/libc.so.7 (0x800819000)


2013年10月20日日曜日

[FreeBSD] style(9) 単語

man style(9) の翻訳で分からなかった単語の意味を列挙します。

implicit 暗に示す
assume 思い込む
silent on 言及しないで
History is silent on this event. 歴史は、この事件に関しては何も記していない。
brevity 簡潔な
trim 削減する
onlike in this one これとは違って
obtain B from A AからBを得る
elsewhre そのほかの場所では、
(a) applicable 適用可能である
enclose 囲む
okay to A Aして大丈夫です。
side effect 副作用
either どちらか一方
parentheses 確固
expantion 拡張
right-justigy 右寄せにする
encapsulate 要約する
compound statement 複合ステートメント
invocation 呼び出し
conditionally 条件的に
discern がわかる。はっきりと認める。
subjectively 主観的に
corresponding 一致する、対応する
preceding 先行する、前述の、上記の、先立つ
abbreviate 略して書く
identifier 識別子
in preference to A Aに勇戦して。 Aよりはむしろ。
overiding 他の全てに優先する
qualifier 修飾語句
suffice 満足させる
know if A is B AがBであるかどうかを知る
whereas であるのに ところが に反して
convention 慣習 しきたり、
elsewhere ほかの場所
relevant a 関連のある
preferably なるべく むしろ 好んで
compelling 強制的な むりやりの
precedent 慣例
either A or B AまたはB A,Bのどちらでも A,Bのいづれかを
preferable より好ましい
line up 整列する
briefly 簡単に
consistency 一貫性
obvioud 明白な
complicate 複雑にする
unary 単項の
binary operator 二項演算子
precedence 先行、上位
obvious 明白な
desire 強く願う
elicit 誘い出す、引き出す
complaint 不平、ぐち
whatever〜 どんな〜でも
compliant with に従う
consistent with 調和して、矛盾しないで
apporoximately ほぼ
diverge 分岐する、離れる
desire 要望
practice 実践



[FreeBSD] style(9) 難訳箇所について

man style(9) の翻訳で訳すのが難しいと感じた箇所について日本語翻訳マニュアルの訳を見てみます。

1) Be careful to check the examples before assuming that style is silent on an issue.

-> styleがこれらの例について言及していないと決めつける前に、注意して例を確認してください。

assume: 決め付ける

2) All VCS (version control system) revision identification in files obtained form else where should be maintained.

->  全てのVCS(バージョン官吏システム)リビジョン識別子は、存在すれば維持します。

obtain: 手に入れる
maintain: 維持する、持続する


3) In declarations, do not put any whitespace between asterisks and adjacent tokens, except for tokens that are indentifiers related to types.

-> 宣言の中では、型に関係づけられたトークンを除いて、アスタリスクと隣接したトークンの間には空白文字を置きません。

4) for example you need to know if the typedef is the structure itself or a pointer to the structure.

-> 例えば、typedefが構造体そのものであるか、構造体へのポインタであるのか、あなたか知る必要があります

A need to know if B.: Aは、Bであるかを知る必要がある。

5) In general code can be considered "new code" when it makes up about 50% or more of the file(s) involved.

-> ファイルの50%以上かそれ以上を巻き込んだ修正の場合は一般にコードは、”新しいコード"とみなすことができます。

involve: 巻き込む

6) ANSI C says that such declarations have file scope regardless of the nesting of the declaration.

-> ANSI Cによるとこの様な宣言は、宣言のネスティングによらず、ファイルスコープになります。

regardless of A: Aにもかかららず


7) Code that is approximately FreeBSD KNF style compliant in the repository must not diverse from compliance.

-> リポジトリの中のおおよそFreeBSD KNF style に適合しているコードは、この適合から離れてはなりません。

compliant: 準拠している
diverse: 別種の、異なった


2013年10月15日火曜日

[FreeBSD] styleの自力和訳

英語の鍛錬のためにstyle(9)を自力で英訳してみた。

FreeBSD カーネル開発者用マニュアル

#NAME#
   style -- カーネルソースファイル書式ガイド

#DESCRIPTION#

このファイルでは、FreeBSDソース群の中でもカーネルソースファイルの推奨される
書式を規定している。またこれは、ユーザー向けのプログラムのコードの書式
ガイドでもある。多くの書式規則が例文とともに示されている。その書式が
重要な点について記していないと思う前によく例をチェックされい。

/*
* FreeBSDの書式ガイド。CSRGのカーネル標準書式(KNF)に基づいた。
*     @(#)style     1.14 (Barkeley) 4/28/95
* $FreeBSD release/9.1.0/share/man.style.9 217807 2011-01-07 08:34:12Z trasz $
*/

/*
* "とても"重要な1行のコメントは、この様に書く。
*/

/*
* 複数行のコメントは、この様に書く。普通の文章と同じように。普通の文章の
* 段落分けと同じように記述する。
*/

著作権の表示は、複数行であるべきだ。一行目は、アスタリスクの後にダッシュを続け
次の様に書く。

/*-
* Copyright (c) 1982-2025 John Q. Public
* All rights reserved.
*
* 長く退屈なライセンスは、ここに書く。しかし、完結かつ短く。
*/

スクリプトは、ソースツリーから"/*-"から始まるコメントの全てをライセンス情報として収集する。
もし、indent(1)の1文字目から始まるライセンスや著作権表示ではないコメントを再整形しないフラグ
を立てることを望む場合は、そのコメントのダッシュをアスタリスクに変更せよ。1行目以外の
コメントは、ライセンス文として考慮されない。

著作権ヘッダーの後に、空行を入れる。そして、C/C++以外のソースファイルのための$FreeBSD$。
バージョンコントロールIDタグ一つのファイルに1つのみ含まれるべきである(これとは違い)。
C/C++以外のソースファイルは、上記の例の様にあるべきである。C/C++のソースファイルにおいては、
以下の1つに準拠する。ファイルの全てのVCS(Version control system) の版は、
その他のファイルでは、メンテナンスされ、含まれ、適用可能で、複数のIDがファイルの履歴を
示す。総じて、外部のIDとインフラを編集すべきではない。ラップされることなしに("#if
defined(#LIBC_SOCS)")、非互換のビットを隠し、IDをオブジェクト
ファイルに含ませないために"#if 0... #nedif"で囲む。ファイル名が変更された
場合、外部のVCSIDの直前にのみ"From: "を追加する。

#if 0
#ifndef lint
static char sccsid[] = "@(#)style 1.14 (Barkeley) 4/28/95":
#endif /* not lint */

#endif

#include <sys/cdefs.h>

__FBSID("#FreeBSD: release/9.1.0/share/man/man9/style.9 217087 2011-01-07 08:34:12Z trasz $"):

ヘッダーファイルの前のその他の空行は、そのままにしておく。

通常は、カーネルのインクルードファイル(例: sys/*.h)が最初に来る。
<sys/types.hと<sys/param.h>の両方ではなく、どちらか一方をインクルードする。
<sys/types.h>は<sys/coefs.h>インクルードする。そして、<sys/types.h>は、
<sys/coefs.h>に依存して問題ない。

#include <sys/types.h> /* ローカルではないインクルードは、<>で囲む */

ネットワークプログラムにおいては、次にネットワーク関係のインクルードファイルを次に書く。

#include <net/if.h>
#include <net/if_dl.H>
#include <net/route.h>
#include <netinet/in.h>
#include <[protocolos/wrhod.h>

カーネルのソースに/usr/includeにあるファイルを使ってはいけない。

次のグループの前に空行を置く。/usr/includeにあるファイルは、アルファベット順で
ソートされていなければいけない。

#include <stdio.h>

グローバルなパスは、<paths.h>で定義されている。プログラム固有のローカルパスは、
ローカルの"pathnames.h"に記述する。

#include <paths.h>

ユーザー固有のインクルードファイルの前に空行を置く。

#include "pathnames.h" /* ローカルのインクルードファイルは、ダブルクオートでくくる*/

実装名前空間でアプリケーションインターフェースを実装する場合を除いて#define したり名前
を宣言してはいけない。

"unsafe"マクロの名前(副作用を伴う)と内容が明白なマクロの名前は、全て大文字にする。
語句のようなマクロの拡張は、一つのトークンか括弧の外を持つ。#defineと
マクロ名の間には、タブ一つを置く。もしマクロがインライン関数の拡張ならば、関数名は、全て小文字
にする。読みやすくするためにバックスラッシュを右寄せにする。もし、マクロが複合ステートメント
ならば、それをdoループで囲む。そうすればif文の中で安全に使うことができる。文章の終端の
セミコロンは、華奢なプリンターやエディタのパースを簡単にするべくマクロよりむしろ
マクロの呼び出しによっておかれるべきだ。

#define MACRO(x, y) do { \
variable = (x) + (y); \
(y) += 2; \
} while(0)

コードが#ifdefや#ifを使い条件的にコンパイルされる時、マッチする#endifや
#elseに続き、読み手が容易に条件付きコンパイルのコード部分の終わりが
分かるようにコメントを追加するかもしれない。そのコメントは、
(主観的に)当該コード部分が長いと思われる場合、20行を越える場合、#ifdef
のネストが読み手を混乱させる可能性がある場合にのみ用いられるべきである。
例外は、lint(1)の目的のために条件付きコンパイルされない複数のケースのために作られるかもしれ
ない。これは、コンパイルされるコードが少ない場合においてさえそうである。コメントは、
1つのスペースで#endifや#elseと離すべきである。短い条件付きコンパイル部分に対しては、
近接したコメントは、つけるべきではない。

#endifへのコメントは、対応する#if、#fidefと表現を一致させるべきである。#else,#elif
へのコメントは、先行する#if、#elif文と逆の表現とすべきである。コメントにおける、
"defined(FOO)"のような準表現は、"FOO"と略される。コメントの目的は、"#ifndef FOO"は、
"#if !defined(FOO)"として扱われる。

#ifdef KTRACE
#include <sys/ktrace.h>
#endif
#ifdef COMPAT_43
/*A large region here, or other condional code. */
#else /* !COMPAT_43 */
/* Or here. */
#endif /* COMPAT_43 */

#ifndef COMPAT_43
/* Yet another large region here, or other conditional code. */
#else /* COMPAT_43 */
/* Or here */
#endif /* !COMPAT_43 */

プロジェクトは、古いBSDスタイルのu_intxx_t式の整数識別子よりむしろISOIEC 9899:1999
("ISO C99") uintxx_t式の符号無し整数の識別子を使うべくゆっくり動いている。新しい
コードは、後者を使うべきである。そして、もし、他の主要な作業が終わり格別の理由がなければ
そのエリアにある古い様式を、新しい様式に変換すべきである。何もないコミットの様に、ケアは、uintxx_tのみのコミットにすべきである。

列挙型の値は、全て大文字である。

enum enumtype {ONE, TWO} et;

識別子における内側の_アンダースコアの使用は、cammelCaseやTitleCaseにもまして
好まれる。

宣言部においては、トークンが型に関連した識別子である場合を除いて隣接したトークンと
アスタリスクの間にスペースを開けてはいけない。(それら識別子は、基底型の名前、修飾子、
独立して宣言されるものと言うよりむしろtypedefで定義されるものである。)
それら識別子は、スペース一つでアスタリスクと分けなさい。

構造体のメンバを宣言する時、使用する順番、サイズ(大きいものから小さいもの)
、アルファベット順でソートして宣言しなさい。最初のカテゴリは、通常適用されない。
しかし、例外がある。1つのメンバーは、1行で宣言しなさい。可読性を向上させるため
メンバー名をあなたの裁量で1つまたは2つのタブで整列するよう努めなさい。一つのタブは、
少なくともメンバーの90%が揃う場合にのみ使用するべきである。とても長い型に続く
名前は、スペース1つで分離すべきである。

主要な構造体は、構造体が使われるファイルの先頭で宣言するすべきである。
また、構造体が複数のソースで使われる場合は、ヘッダーファイルに分離すべきである。
構造体の使用部と宣言部は、分離すべきであり、ヘッダーファイルで宣言されている
場合は、externすべきである。

struct foo {
struct foo *next; /* List of active foo */
struct mumblue amumble; /* mumble のコメント    */
int bar; /* コメントを揃えるように */
strcut verylongtypename *baz /* 2つのタブで揃わない場合 */
};
struct foo *foohead; /* グローバルなfooリストの先頭 */

可能な時は常に、自分でリストを回すのではなくてquese(3)マクロを用いよ。
従って、前述の例は、次の様に書くのが好ましい。

#include <sys/queue.h>

struct foo {
LIST_ENTRY(foo) link; /* fooリストには、queueマクロを用いる */
struct mumble amumble; /* mumbleのコメント */
int bar; /* コメントを揃えるように。 */
struct verylongtypename *baz; /* 2つのタブで揃わない場合 */
};
LIST_HEAD(, foo) foohead; /* グローバルなfooリストの先頭 */

構造体の型にtypedefsを用いるのは、避けなさい。Typedefsは、元の型を適切に
隠さないので、問題を抱えがちである。例えば、typedefが構造体自身もしくは構造体への
ポインターかどうかを知る必要がある。加えてそれらは、正確に1回宣言しなければいけない。
ところが、不完全な構造体の型は、不必要であるにもかかわらず何回も記述することができる。
Typedefsは、独立したヘッダーファイルで用いいるのが難しい。typedefを定義するヘッダーは、
用いられるヘッダーより以前に、用いられるヘッダによって(名前空間の汚染をもたらす)インクルード
されなければいけない。また、それらは、typedefを含むことに対するバックドアでなければいけない。

慣習がtypedefを必要とするとき、その名前は、構造体のタグ名と一致させるべきである。Standard C
もしくはPOSIXで指定されている場合を除いてtypedefの最後を"_t"とするのは避けなさい。

/* 構造体の名前は、タグ名と一緒にせよ */
typedefi struct bar {
int level;
} BAR;
typedef int foo; /* これは、foo */
typedef const long baz; /* これは、baz */

全ての関数は、どこかでプロトタイプ宣言されている。

(ほかの場所から使われない)プライベートな関数のプロトタイプ宣言は、ソースコードの
一番最初に持っていくべきである。ソースコード内のみで使われる関数は、staticと
宣言すべきである。

カーネルの別の部分から使われる関数は、関連のあるインクルードファイルでプロトタイプ宣言される。
関数のプロトタイプ宣言は、論理的順序で列挙するべきである。他の順番を使う
明白な理由がない場合は、なるべく、アルファベット順を使うべきである。

一つ以上のモジュールから使用されるローカルな関数は、"extern.h"のような別のヘッダーファイルに
含めるべきである。

__Pマクロを用いるべからず。

総じて、50%以上ファイルが影響を受けるコードは、"新しいコード"と認識される。これは、
既存のコードの慣例を崩すのに十分である。現在のstyleガイドラインに従いなさい。

カーネルは、パラメータの型にに関連付けられた名前を持つ。以下カーネルでの使用例。

void function(int fd);

ヘッダーファイルにおいては、ユーザーランドのアプリケーションに対して見えるようにせよ。
見えるプロトタイプ宣言は、(アンダーバーから始まる)"protected"な名前か名前のない型のどちらか
を用いなければいけない。purotectedな名前を使う方が好まれる。

void function(int);



void function(int _fd);

プロトタイプ宣言は、関数の名前を揃えるためにタブの後に多くのスペースを含むかもしれない。

static char *function(int _argc, const char *_arg2, struct foo *_arg3,
                     struct bar *_arg4);
static void *usage(void);

/*
* 全ての主要なルーチンには、何をするかということを簡単に説明したコメントをつけるべきである。
* mainルーチンの前のコメントは、このプログラムが何をするかを説明すべきである。
*/
int
main(int argc, char *argv[])
{
char *ep;
long num;
int ch;

一貫性のために、オプションをパースするときは、getopt(3)を用いるべきである。
オプションは、switch文の一連の流れの一部ではなく、getopt(3)の呼び出しとswitch文の中で
ソートされるできである。switch文の中の要素であるcascadeには、FALLTHROUGHコメントを
つけるべきである。数の引数に対しては、精度をチェックすべきである。明白な理由に到達不可能な
コードは、/* NOTREACHED */とマークされるかもしれない。

while((ch = getopt(arc, argv, "abNn:")) != -1)
switch (ch) { /* switch文をインデントせよ */
case 'a': /* case文はインデントしない */
aflag = 1; /* case文本体は、1つのタブでインデント */
/* FALLTHROUGH */
case 'b':
bflag = 1;
break;
case 'N':
Nflag = 1l
break;
case 'n':
num = strtol(optarg, &ep, 10);
if (num<= 0 || *ep != '\0') {
warnx("illegal number, -n argument -- %s",
      optarg);
usage();
}
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;

 (if, while, for, return, switch)の後には、スペースをいれよ。ステートメントが
一行以上になる許される場合の除いてゼロもしくは1ステートメントと共にブレース("{""}")を
ステートメントを制御するために用いてはいけない。無限ループは、whileではなく、forを用いよ。

for (p = buf; *p != '\0'; ++p)
/* nothing */
for (; :)
stmt;
for (; :) {
z = a + really + long + statement + that + needs +
   two + lines + gets + indented + for + spaces +
   on + the + second + and + subsequent + lines;
}
for (; ;) {
if (cond)
stmt;
}
if (val != NULL)
val = realloc(val, newsize);

 forループの一部は、空になるかもしれない。ルーチンが特殊で複雑な場合を除いてブロック内で
宣言をしてはいけない。

for (; cnt < 15l cnt++) {
stmt1;
stmt2;
}

 インデントは、8文字のタブにすること。2段目のインデントは、4つのスペースにすること。もし、
長いステートメントとなる場合は、演算子を行の最後に書くこと。

while (cnt < 20 && this_variable_name_is_too_long &&
   ep != NULL)
z = a + really + long + statement + that + needs +
   two + lines + gets + indented + four + spaces +
   on + the + second + and + subsequent + lines;
 行末に空白を入れては、いけない。タブは、空白の後ろにインデントを揃えるためにのみ使いなさい。
タブよりも多くのスペースを使ってはいけない。タブの前にスペースを入れてはいけない。

 ブロックの始まりと終わりのブレースは、elseと同じ行に書きなさい。不必要なブレースは、
いれない。

if (test)
stmt;
else if (bar) {
stmt;
} else
stmt;

  関数名の後にスペースを入れない。コンマの後には、スペースを入れよ。'('や'["の後に
スペースを入れない。')'や']'の前にスペースを入れない。

error  = function(a1, a2);
if (error != 0)
exit(error);

 単項演算子にスペースは、必要ない。二項演算子には、スペースが必要である。優先させる必要がある
場合や複雑なステートメントの場合を除いて()を使ってはいけない。他人は、自分より
混乱しやすいかもしれないということを覚えておこう。下記のコードが理解できるか?

a = b->c[0] + ~b == (e || f) || g && h ? i : j >>1;
k = !(l & FLAGS);

 処理に成功した場合は、0を返し、失敗した場合は、1を返せ。

exit(0); /*
 * "処理成功時は、0を返す"の様な
 * 明白なコメントは、避けよ。
 */
}

関数の返り値の型は、"function"の前の行に書きなさい。関数の中身を書くための右ブレースは、
1行に書きなさい。

satic char *
function(int a1, int a2, float fl, int a4)
{

 関数内で変数を宣言する時、サイズ順->アルファベット順で宣言しなさい。複数の変数を
1行でまとめて宣言するのは、OK。もし、一つの型の変数が1行に収まらない時は、複数行に
分けて、型名を行頭に書きなさい。宣言部で変数を初期化することによってコードが
分かりにくくなることのない様に気を付けなさい。このことについては、あまりシビアに
ならなくても良い。初期化部において関数の呼び出しをしてはいけない。

struct foo one, *two;
double three;
int *four, five;
char *six, seven, eight, nine, ten, elven, twelve;

for = myfunction();

 関数の中で関数を宣言しては、いけない。ANSI Cにおいては、そのような
不注意な入れ子の宣言は、ファイルスコープを持つ。ローカルスコープに現れる
ファイルスコープは、思わぬ不平を良いコンパイラから引き出す。

キャストとsizeofの後にスペースを入れては、いけない。ちなみに、indent(1)は、
このルールに依らない。sizeofは、丸括弧とともにかかれる。sizeof(var)インスタンスに
冗長な丸括弧のルールを適用しては、いけない。

 NULLは、空のポインタ定数を好む。アサイメント等コンパイラが型を知っているコンテキストにおい
ては、(type *)0や(type *)NULLの代わりにNULLを使え。その他のコンテキスト、特に全ての関数の
引数においては、(type *)NULLを使え。(もし、関数のプロトタイプ宣言がスコープにない場合、キャ
ストは、可変長引数においては必要であるが、その他の引数に対しては、不必要である。)
ポインタのNULLチェックの例

(p=f()) == NULL

悪い例:

!(p = f())

論理型でないにもかかわらず、チェックに!を使うな。次の様にすべきである。

IF (*p == '\0')

悪い例:

if (!*p)

 void *を返すルーチンは、返り値を勝手にキャストして返してはいけない。
 return文における値は、丸括弧で囲むべきである。

 err(3)やwarn(3)を使え。自分で実装するな。

if ((four = malloc(sizeof(struct foo))) === NULL)
err(1, (char *)NULL);
if ((six = (int *)overflow()) == NULL)
errx(1, "number overflowwed")'
return (eight);
}

 この様な古い様式の関数宣言。

static char *
function(a1, a2, f1, a4)
int a1, a2; /* 整数型の宣言。これらをデフォルトにしてはいけない。*/
float f1; /* floatとdoubleのプロトタイプの違いに注意せよ。 */
int a4; /* 順番が宣言されたリスト */
{

 明白にK&Rとの互換性が必要な場合を除いて、ANSIの関数宣言を使いなさい。長いパラメータの
リストは、4つの普通のスペースでインデントしなさい。

 可変長の引数は、次の様にすべきである。

#include <stdarg.h>

void
vaf(const char *fmt, ...)
{
vs_list ap;

va_start(ap, fmt);
STUFF;
vs_end(ap);
/* void型を返す関数においては、return文は不要である */
}


static void
usage()
{
/* 関数に、ローカル変数がない場合は、空行を入れる。 */

 どんなにそれが、早くきれいだとしても、おろかなバグに気を使わなくても良いように
fputs(3),puts(3),putchar(3)ではなくて、printf(3)を使いなさい。

 Usage文は、マニュアルページのSYNOPSISのようにあるべきである。そして、
下記順番になっているべきである。

1.  オペラントの必要ないオプションを一番最初仁1組のラケット"[]"の内側にアルファベット順
で書く。
2.  オペランドが必要なオプションを次に、同じくアルファベット順でブラケットの内側に書く。
3.  必要な引数があれば、次にコマンドラインで指定すべき順序で書く。
4.  最後に、残りの任意の引数をブラケットの内側に同じくコマンドラインで指定すべき
順序で列挙する。

 バーは、"どちらか一方の"オプション、引数を分離する。共に指定すべき複数のオプション、引数は、
一組のブラケットの内側に書く。

"usage: f [-aDde] [-b b_arg] -m m_arg] req1 req2 [opt1 [opt2]]\n"
"usage: f [-a | -b] [-c [-dEe] [-n number]]\n"

(void)fprintf(stderr, "usage" f [ab]\n");
exit(1);
}

 マニュアルのオプションの説明は、純粋にアルファベット順であるべきだ。これは、オプションが
引数を取る/取らないにかかわらない。また、大文字小文字の順で示すべきだ。

 現在、カーネルコードは、styleガイドに従うべきである。サードパーティによるモジュールや
ディバイスドライバのガイドラインは、より緩和的である。しかし、最低限内面的に
それらのstyleと矛盾しないようにすべきである。

 様式的な変化(空白の変化も含め)は、ソースリポジトリにとって重大であり、良い理由を除いて
避けなければいけない。リポジトリにおけるFreeBSD KNF style規則のコードは、コンプライアンス
から逸脱してはいけない。可能な時は、いつでもコードをコードチェッカー(lint(1)やgcc -Wall
にかけ、警告を最小限に減らすべきである。

#SEE ALSO#
 indent(1), lint(1), err(3), warn(3), style.Makefile(5)

#HISTORY#
 このマニュアルページのほとんどは、4.4BSD-Lite2 release の src/admin/style/styleの
ファイルに基づき、日々の更新は、現在のFreeBSDプロジェクトの要望と実践に反映されている。
src/admin/style/style は、Ken ThompsonとDenis RitchieのAT&T UNIX Version 6に
おけるプログラミング様式のCSRGである。

2013年9月28日土曜日

[xfce] uim-anthy-gtk-systray をログイン時に実行

表記の件について

[Applications Menu - Settings - Session and Startup] をクリック。

「Seccion and Startup」ダイアログの「Application Auotstart」タブを選択して。

「uim-toolbar-gtk-systray」を追加します。



ちなみに、設定ファイル弄る方法を初め模索しましたが「uim-toolbar-gtk-systray」が実行されるタイミングが悪く(ファイルの編集方法が悪く)諦めました。

2013年9月24日火曜日

[FreeBSD] Installing flash plugin

Environmente: FreeBSD 9.1-RELEASE


If you installed emulators/linux_base-f10

You only to run

kldload linux

And add following line to /etc/rc.conf

linux_enable="YES"


And reference

7.2.1.2. Firefox and Adobe® Flash™ Plugin

[FreeBSD] compiling chromium browser

I compiled chromium browser(Version 29.0.1547.76) on FreeBSD 9.1-RELEASE.


[Point of compiling chromium browser]
compile with out debug symbol
When I compiled chromium with debug symbol. chrome aborted by signal 16.


$ cd /usr/ports/www/chromium/
$ make config-recursive
$ make
$ make install


And add follwoing line to  /etc/syctl.conf

kern.ipc.shm_allow_removed=1

So you can run chromium browser.

$ chrome # not chromium

2013年9月23日月曜日

[Office Suite] docx pptx xlsx について

「docx pptx xlsx」という一連の「*x」というフォーマットは、zipでxmlファイル群圧縮しているらしい。
PyCon 2013 の kzfmさんの資料を参考にさせて頂き実践してみた。

まず、サンプルのパワーポイントスライドを作って「sample.pptx」で保存する。


そして、sample.pptxを解凍する。
$ unzip sample.pptx
解凍すると下記のようなファイルが出てくる。
その中の「ppt/slides/slide1.xml」がスライドの内容となるので、適当なエディタで編集する。



再びZipで圧縮して、「after.pptx」とする。
$ zip -r after.pptx \[Content_Types].xml docProps/ ppt/ _rels/
Power Pointで圧縮したafter.pptxを開いてみる。






[pptxを解凍して出てきたファイル群]
$ tree
|-- [Content_Types].xml

|-- _rels

|-- docProps

|   |-- app.xml

|   |-- core.xml

|   `-- thumbnail.jpeg

|-- file.lst

|-- ppt

|   |-- _rels

|   |   `-- presentation.xml.rels

|   |-- presProps.xml

|   |-- presentation.xml

|   |-- slideLayouts

|   |   |-- _rels

|   |   |   |-- slideLayout1.xml.rels

|   |   |   |-- slideLayout10.xml.rels

|   |   |   |-- slideLayout11.xml.rels

|   |   |   |-- slideLayout2.xml.rels

|   |   |   |-- slideLayout3.xml.rels

|   |   |   |-- slideLayout4.xml.rels

|   |   |   |-- slideLayout5.xml.rels

|   |   |   |-- slideLayout6.xml.rels

|   |   |   |-- slideLayout7.xml.rels

|   |   |   |-- slideLayout8.xml.rels

|   |   |   `-- slideLayout9.xml.rels

|   |   |-- slideLayout1.xml

|   |   |-- slideLayout10.xml

|   |   |-- slideLayout11.xml

|   |   |-- slideLayout2.xml

|   |   |-- slideLayout3.xml

|   |   |-- slideLayout4.xml

|   |   |-- slideLayout5.xml

|   |   |-- slideLayout6.xml

|   |   |-- slideLayout7.xml

|   |   |-- slideLayout8.xml

|   |   `-- slideLayout9.xml

|   |-- slideMasters

|   |   |-- _rels

|   |   |   `-- slideMaster1.xml.rels

|   |   `-- slideMaster1.xml

|   |-- slides

|   |   |-- _rels

|   |   |   `-- slide1.xml.rels

|   |   `-- slide1.xml

|   |-- tableStyles.xml

|   |-- theme

|   |   `-- theme1.xml

|   `-- viewProps.xml

`-- sample.pptx



11 directories, 38 files








[D3] SVG Path

D3を用いたSVGのPathの描画





ソースは、こちら
Path.prototype = {
    constructor: Path,
    readNodesData: function()
    {
        this.lineNodes = [ 
                        {"x": 1, "y": 5}, {"x": 20, "y": 20},
                        {"x": 40, "y": 10}, {"x": 60, "y": 40},
                        {"x": 80, "y": 5}, {"x": 100, "y": 60}
                      ];
        return;
    }

};

function Path()
{
    this.lineNodes;

    this.svg =  d3.select("#drawArea").append("svg")
                 .attr("width", 100)
                 .attr("height", 100);

    this.lineFunction = d3.svg.line()
                              .x(function(d){return d.x;})
                              .y(function(d){return d.y;})
                              .interpolate("linear");
    this.readNodesData();

    this.line = this.svg.append("path")
                   .attr("d", this.lineFunction(this.lineNodes))
                   .attr("stroke", "blue")
                   .attr("stroke-width", 2)
                   .attr("fill", "none");
    return;
}

2013年9月19日木曜日

[Python] Memo about list

記憶の定着を図るためのメモ

#del について
>>> list = [0,1,2]
>>> del list[1]
>>> list
[0, 2]
>>> list [0]
0
>>> list [1]
2
# リストに対する += 演算子
>>> slots = []
>>> slots += [0,0]
>>> print slots
[0, 0]
>>> slots += [1,1]
>>> print slots
[0, 0, 1, 1]
>>>

2013年9月18日水曜日

[Python] Difference between list and tuple

Python初心者の自分としては、よく分からなかった。
記述方法の違いしか分からなかった。(大括弧囲みか丸カッコ囲みか)

しかし、違いがもう一つわかった。
リスト(List) -> 値の再代入ができる
タプル(Tuple) -> 値の再代入ができない

試しに、、、

>>> vec = [2,4,6]
>>> list = [[x,x*2] for x in vec] # リストの生成
>>> print list
[[2, 4], [4, 8], [6, 12]]
>>> tuple = [(x,x*3) for x in vec] #タプルの生成
>>> print tuple
[(2, 6), (4, 12), (6, 18)]
>>> list[0][1] = 5 # リストに値を再代入してみる
>>> print list
[[2, 5], [4, 8], [6, 12]] #代入できている
>>> tuple[0][1] = 7 #タプルに再代入してみる
Traceback (most recent call last): # タプルは、アイテムのアサインをサポートしていないとおっしゃてる
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> print tuple
[(2, 6), (4, 12), (6, 18)]
>>>

2013年9月16日月曜日

[D3] 事始め

D3 (Data-Driven Documents) を試した。今回の着目点は、
1.SVGに要素を追加
2.追加した要素に読み込んだデータをアサインする data(dataset)
3.アサインしたデータに基づいた要素属性の設定(特に色
4.描画系とデータという異なる座標値を変換する scale
5.軸の追加

参考ページ: http://alignedleft.com/tutorials/d3
上記ページは、D3の概要を知るには、よくまとめられていて大変参考にさせて頂きました。

サンプルついて
散布図の描画をイメージしたものでRunボタンを押すとランダムな位置に大きさの異なる。5つの円が描画されます。円の色については、色のrangeを使って自身の大きさが小さいほど青、大きいほど赤になるようにしています([A])。
Updateボタンを押すとその都度円の位置が変わります([B])。



ソース
ScatterSample.prototype = {
    constructor: ScatterSample,

    circleFillColor: function(d)
    {
        var color = d3.scale.linear().domain([0,30]).range(['blue','red']); //[A]
        return color(d);
    },

    mkCirclePosData: function()
    {
        var random = Math.random();
        random = (random - 0.5) * 2.0;
        return random;
    },

    changeCirclesPos: function() // [B]
    {

        svg = d3.selectAll('svg');
        circles = svg.selectAll('circle');
        circles.attr("cx", function(){
                        pos = ScatterSample.prototype.mkCirclePosData();
                        return ScatterSample.xScale(pos);
                    })
               .attr("cy", function(){
                        pos = ScatterSample.prototype.mkCirclePosData();
                        return ScatterSample.yScale(pos);
                    })
 
         return;
    }

};

function ScatterSample()
{

    var dataset = [5, 10, 15, 20, 25];

    this.width  = 500;
    this.height = 300;

    ScatterSample.xScale = d3.scale.linear()
                         .domain([-1, 1])
                         .range([50, this.width-50]);

    ScatterSample.yScale = d3.scale.linear()
                         .domain([-1, 1])
                         .range([50, this.height-50]);

    var svg = d3.select("#drawArea")
                .append("svg") // 1.
                .attr("width" , this.width)
                .attr("height", this.height);

    var circles = svg.selectAll("circle")
                     .data(dataset) // 2.
                     .enter()
                     .append("circle");
    circles.attr("cx", function(){
                    pos = ScatterSample.prototype.mkCirclePosData();
                    return ScatterSample.xScale(pos); // 4.
                })
           .attr("cy", function(){
                    pos = ScatterSample.prototype.mkCirclePosData();
                    return ScatterSample.yScale(pos);
                })
           .attr("r", function(d){
                   return d;
               })
            .style("fill", function(d){ // 3.
                    return ScatterSample.prototype.circleFillColor(d);
               });

    var yAxis = d3.svg.axis()
                      .scale(ScatterSample.yScale)
                      .ticks(5)
                      .orient("left");
    svg.append("g") // 5.
       .attr("transform", "translate(50,0)")
       .call(yAxis)
       .selectAll("path,line")
       .attr("fill","none").attr("stroke","black")
       .attr("shape-redering","crispEdges");

    var xAxis = d3.svg.axis()
                      .scale(ScatterSample.xScale)
                      .ticks(5)
                      .orient("bottom");

    svg.append("g")
       .attr("transform", "translate(0,250)")
       .call(xAxis)
       .selectAll("path,line")
       .attr("fill","none").attr("stroke","black")
       .attr("shape-redering","crispEdges");
}


2013年9月15日日曜日

[Qt] 事始め

C++ で記述されたクロスプラットフォームフレームワークQtを試してみた。

URLを入力してアクセスするだけの超簡易Webブラウザを作ってみた。作ってみたと言っても書いたコードは、数行。FreeBSD 、Windows 7, Windows XP で動かしてみた。

  




まずは、FreeBSD(xfce)にて
Qt 関連のライブラリが含まれる「Qt」本体(Ver.4.8.2)とQt のIDEである「Qt Creator」(Ver.2.5.0)をコンパイル&インストールする。

 cd /usr/ports/devel/qt4
make config-recursive
make
make install

cd /usr/ports/devel/qtcreator
make config-recursive
make
make install


以下がQt Creatorを起動したことろ


まず、コンパイラ関連の設定をする。メインウィンドウの[Tools-Options]でオプションダイアグを開き、ダイアログ左の一覧から「Build & Run」を選択して、「Qt versions」タブを選択。ダイアログ右にある「Add」ボタンをクリックして、先ほどインストールしたQt4本体に含まれる、「qmake-qt4」のPATHを指定します。デフォルトなら、「/usr/local/bin/qmake-qt4」です。



次にどダイアログの「Tool Chains」タブでgcc と gdb のPATHを指定する。ウィンドウ右の「Add」ボタンから「Gcc」を選択。「Compiler path」にgcc(Ver.4.2.1)へのpathを「Debugger」にgdbへのpathを指定する。


これで下準備は、完了。
新しいプロジェクトを作ってコンポーネントをペタペタ貼っていく。


WebブラウザのコンポーネントQWebViewを使った。
コードを数行書く。
-mainwindow.h-
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
 
private:
    Ui::MainWindow *ui;

public slots:
    void updateWebPage();
};

#endif // MAINWINDOW_H


-mainwindow.cpp-

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "mywebview.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(ui->goButton, SIGNAL(clicked()), this, SLOT(updateWebPage()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::updateWebPage()
{
    ui->webView->setUrl(QUrl(ui->lineEdit->text()));
}

Qtの場合イベントを「Signal」といいイベントハンドラを「Slot」という。メインウィンドウのコンストラクタにて、connect関数にて、clicked()というSignalのスロットとしてupdateWebPage()というインプットボックスに入力されたURLをロードする関数を登録する。詳しくは、こちらを参照されたし。

そして、IDE左下の「Run」または、Ctrl+Rで実行できる。


次は、Windows 7で実行してみる。環境がウィンドウズに変わるので再コンパイルが必要です。
C++のコンパイラには、Visual Studio C++付属のclを用います。よってVisua C++ 2010 Expressをインストールしておきます。

さらにQt本体(こちらはバイナリ) (Ver.4.8.2) と Qt Creator (Ver.2.5.2)をDLして、インストールする。
FreeBSDの場合と同様Qt Creatorを起動して、qmakeのpathを指定します。デフォなら「C:\Qt\4.8.2\bin」です。

つぎに、C++コンパイラですが「ツールチェイン」タブにて自動検出されているはずですので手動指定する必要はありません。

FreeBSDで作成した、プロジェクトファイルとコードをWindowsマシンに持ってきて「*.pro」のプロジェクトファイルを開きます。そして、ビルドします。


コンパイルが通ったら早速exeを直接実行したいところですが、Qt関連のライブラリのPATHが通っていないので環境変数PATHにqmakeと同じPATH(C:\Qt\4.8.2\bin\)を追加します。



追加が終わったら直接exeを実行することができます。


次は、先ほどWIndows 7でビルドしたexeをWindows XPで実行します。Qt4のライブラリは、必要なのでQt本体をDLしてインストール、qmakeへのパスを環境変数PATHに追加しておきます。

これで実行可能になりました。






2013年9月5日木曜日

[Python] ファイルからの読み込み

超今更なエントリですが、自分自身の知識の定着を図るために書きます。
と言ってもコードは、数行

fp = open('./data/router.log', 'r')
for line in fp:
  print type(line)
  print line[:-1].split(' ')
fp.close()


-出力-
<type 'str'>
['2013/04/09', '00:55:45:', 'PP[01]', 'IP', 'Commencing', '(DNS', 'Query', '[www.asial.co.jp]', 'from', '192.168.100.2)\r']
<type 'str'>
['2013/04/09', '00:55:46:', 'PP[01]', 'IP', 'Commencing', '(DNS', 'Query', '[api.twitter.com]', 'from', '192.168.100.2)\r']
<type 'str'>

line は、str型なのでsplitメソッドでリストに分解してます。
一行ずつの読み込みは、

fp.readline()

とする方法もあるが、最初の例のほうが高速らしい、

2013年8月14日水曜日

[Python] モジュールのサーチパス表示

Python モジュールのサーチパスの表示方法 ( 以下は、Mac OS X での実行結果

>>> import sys
>>> print sys.path

['', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages', '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload', '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC', '/Library/Python/2.7/site-packages']

2013年8月6日火曜日

[python] COMコンポーネントを利用してみる

今回は、WindowsにてpythonでCOMコンポーネントを利用してみます。
pythonは既にインストール済みとして、

まず、必要なライブラリをインストールします。

http://sourceforge.net/projects/pywin32/

からインストールされているpythonのバージョンのインストーラーをダウンロードして、インストール。
これで、[python-install-dir]\Lib\site-packages にライブラリがインストールされます。


次に自分の環境にどのようなCOMコンポーネントがインストールされているか確認する。
Windows SDKをインストールして。以下を管理者権限で実行。

regsvr32 "c:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\IViewers.Dll"

そして、Oleview.exeを管理者権限で実行。ちなみに自分の環境では、C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin に当該プログラムがインストールされていた。

ツリーの「Type Libraries」で各COMコンポーネントのインタフェースを確認することができる。


次に、各タイプライブラリのpython用ソースを生成する。win32com clientのインストールディレクトリに移動して、
cd C:\usr\local\python\2_7_5\Lib\site-packages\win32com\client
以下を実行
python makepy.py 

すると利用可能なタイプライブラリの一覧が表示されるので。ソースを生成したいライブラリを選択して「OK」を押下。

 ここでは、iTunesを選択してみた。生成したタイプライブラリの情報は、

python make.py -i "iTunes 1.13 Type Library"

で確認することができる。

さてようやくサンプルコードですが。。。

>>> import win32com.client
>>> foo = win32com.client.Dispatch("iTunes.Application")
>>> foo.Quit()

ウィンドウを最小化したり、音量を変更したりできるみたいですが今日はここまで



-Reference-
Quick Start to Client side COM and Python

2013年7月30日火曜日

[Network] IPアドレスの衝突

最近普段自分が利用するIPネットワークが不安定にたまにホストの名前解決に失敗する
ネットワークの構成変更をしたばかりでもあり、一番可能性が疑われるIPアドレスの衝突の調査をしてみる。

BSD系OS/Windows
[1] arpテーブルを全て削除
arp -d # BSD系OSの場合 root権限で

[2] テーブルエントリーの追加のために衝突が疑われるアドレスに対してping
ping dst-address

[3] arpテーブルの表示
arp -a

上記手順を数回繰り返して、[3]で表示されるMACアドレスが複数あれば、IPアドレスが衝突していることになる。




2013年7月23日火曜日

[FreeBSD] GUI環境構築

DM に xfce4 を採用してGUI環境を構築したが、シャットダウン、リブートを一般ユーザーが出来ない

これを解決するためには、/usr/local/etc/polkit-1/localauthority/50-local.d/org.freedesktop.consolekit.pkla を作成して以下を記述する

[Local restart]
  Idendity=unix-group:power
  Action=org.freedesktop.consolekit.system.restart
  ResultAny=yes
  ResultInactive=yes
  ResultActive=yes

  [Local shutdown]
  Idendity=unix-group:power
  Action=org.freedesktop.consolekit.system.stop
  ResultAny=yes
  ResultInactive=yes
  ResultActive=yes

  [Local restart - multiple]
  Idendity=unix-group:power
  Action=org.freedesktop.consolekit.system.restart-multiple-users
  ResultAny=yes
  ResultInactive=yes
  ResultActive=yes

  [Local shutdown - multiple]
  Idendity=unix-group:power
  Action=org.freedesktop.consolekit.system.stop-multiple-users
  ResultAny=yes
  ResultInactive=yes
ResultActive=yes

そして、シャットダウン、リブートを許可したいユーザーをpowerグループに所属させる

2013年7月8日月曜日

[FreeBSD] ports チェックサム unmatched

portsにてgmakeをコンパイル、インストールしようとしたら、チェックサムが合わないと言われた。

make distclean

でダウンロードしてきたファイルを削除して

make checksum

でハッシュ値を計算しなおしたらいけた。

[libxml2] XPath によるxmlのパース

APIの多さと初心者向けの情報の少なさで苦戦してますが、ようやく超最低限なパースができたのでメモ


パースするXMLファイル
<?xml version="1.0" encoding="us-ascii" ?>
<orchestra>
  <players num="3">
    <player>aoki</player>
    <player>nakashima</player>
    <player>suzuki</player>
  </players>
</orchestra>

コード
#include <stdio.h>
#include <libxml/xmlreader.h>
#include <libxml/xpath.h>

int main(int argc, char **argv){

  char *xml;
  char *xmlPath;
  int i;

  xmlXPathContextPtr cntxt;
  xmlXPathObjectPtr xmlObj;
  xmlDocPtr doc;
  xmlNodeSetPtr nodes;
  xmlNodePtr node;
  struct _xmlAttr *curAttr;

  xml = argv[1];
  xmlPath = argv[2];
  
  doc = xmlParseFile(xml);
  if(!doc) return -1;
  cntxt = xmlXPathNewContext(doc);
  if(!cntxt) return -1;
  xmlObj = xmlXPathEvalExpression((xmlChar *) xmlPath, cntxt);
  if(!xmlObj) return -1;

  nodes = xmlObj->nodesetval;

  // iterate node
  for(i=0;i<nodes->nodeNr; i++){
    node = xmlXPathNodeSetItem(nodes, i);

    // node name
    printf("=%s=\n", node->name);
    // properties
    curAttr = node->properties;
    while( curAttr != NULL ){
      printf("%s: %s\n", curAttr->name, curAttr->children->content);
      curAttr = curAttr->next;
    }
    if(node->children->content != NULL ){
      printf("content= %s\n",  node->children->content);
    }
  }


  xmlXPathFreeContext(cntxt);
  xmlFreeDoc(doc);
  xmlCleanupParser();

  return 0;
}

実行
./a.out sample/01.xml "//*"

出力
=orchestra=
content= 
  
=players=
num: 3
content= 
    
=player=
content= aoki
=player=
content= nakashima
=player=
content= suzuki


上記サンプルには、値を含んでいないcontentのケアを含んでいない。

参考サイト: http://d.hatena.ne.jp/hakutoitoi/20090319/1237397160 取っ掛かりのコード

2013年6月28日金曜日

[FreeBSD] Sieve を書いてみた

Sieve は、メールフィルタリングのための言語です。

メールサーバー上にフィルタリングルールを定義したファイルを予め置いておき、サーバー上でメールをフィルタリングすることでクライアントの環境に依存しない点が売りです。

今回は、Sieve の Dovecot 向け実装であるPIGENHOLEをインストールしてみました。

[A] インストール

インストール自体は、メールサーバーにて

cd /usr/ports/mail/dovecot2-pgenhole/
make config-recursive
make
make install clean


で終了。

PIGENHOLE のSieve は、Dovecotのプラグインとして提供されているのでこのプラグインを有効にします。この設定は、受信したメールのローカルユーザーへの配信をLDA/LMTPのどちらで行なっているかに依存するので予め確認しておく必要があります。デフォルトでは、LDAを用いているようです。

以下LDAの場合の例 /usr/local/etc/dovecot/conf.d/90-plugin.conf に以下を追加

protocol lda{
  mail_plugins = sieve
}



[B} フィルタリングルール作成

フィルタリングルールは、ルールを適用したいユーザーのホームディレクトリに「.dovecot.sieve」を作成してこのファイルの中に記述していきます。

以下はそのサンプル。

require ["fileinto"];

if address :is "from" "foo@example.jp" {
  fileinto "INBOX.spam";
}


foo@example.jp からのメールをspamフォルダーに振り分けます。そしてこの.dovecot.sieveを以下コマンドでコンパイルして「~/.dovecot.svbin」として出力します。

sievec ~/.dovecot.sieve ~/.dovecot.svbin

これで次回メール受信時から作成したルールが適用されます。ルールが適用されないようであれば~/.dovecot.sieve.log にログが出力されるので参考にします。

今回は、ここまで

今後は、スクリプトファイルのUNICODE対応やThunderbirdのsieveのスクリプトを編集できるAdd On等を試してみたい。。。



2013年6月27日木曜日

[FreeBSD] dovecot2 のインストール

要点のみをかいつまんで。。。

1) コンパイル と インストール

2) 設定ファイル例をコピー
/usr/local/share/doc/dovecot 以下の dovecot.conf と conf.d ディレクトリを /usr/lolcal/etc/dovecot にコピー

3) 認証プロトコルの設定
今回は、テスト用途なんで plain 認証でいきます。 先ほどコピーしたconf.d ディレクトリ中の

10-ssl.conf 中の

#ssl =yes

ssl = no

に変更し、同ディレクトリ中の 10-auth.conf の

#disable_plaintext_auth = yes



disable_plaintext_auth = no

とし、明示的にsslを使わない様に変更。これに気づかずかなり時間を食った

4) デーモンプロセス 始動

/usr/local/etc/rc.d/postfix

起動時に自動でデーモンを起動した場合は、

/etc/rc.conf に以下を追加

dovecot_enable="YES"





2013年6月10日月曜日

[FreeBSD] Windows の共有ディレクトリをマウント

CentOS に続き FreeBSDでも


mount_smb -I host-addr  //host-name/ /mnt/path-to-mount-point


ex) mount_smb -I 192.168.100.2 //win-pc/ /mnt/windir

2013年5月15日水曜日

[Code reading] time command

[Motivation]
FORTRANで記述されコンパイラで自動並列化した数値解析のプログラムの実行時間を下記環境でtimeコマンドを使って測定したら下記の様な結果になった。


-実行環境-
OS: Cent OS
CPU: Intel Xeon Processor L5640 x 2

-並列数-
OMP_NUM_THREAD=12

-time コマンド結果-

real 84m23.521s
user 1010m2.767s
sys 0m7.199s


[reasoning]
user時間は、各コアのuser時間の合計となるためスレッド並列化して実行したコマンドでは、real時間よりも長くなることがある?

[research]


適当なミラーサイトからソースを取ってくる。
後、linuxカーネル(2.6.34)のソースも取ってくる。

まずは、タイムコマンドのmain関数
-time.c: main
632 main (argc, argv)
633      int argc;
634      char **argv;
635 {
636   const char **command_line;
637   RESUSE res;

640   run_command (command_line, &res);
641   summarize (outfp, output_format, command_line, &res);

run_commandという関数を見てみる
-time.c: run_command
597 static void
598 run_command (cmd, resp)
599      char *const *cmd;
600      RESUSE *resp;
601 {

605   resuse_start (resp);

614       execvp (cmd[0], cmd);

623   if (resuse_end (pid, resp) == 0)

timeコマンドで指定したコマンドをexecvp関数で実行している.
execvp関数の前後で呼んでいるresuseで始まる関数を次に見てみる

-resuse.c: resuse_start
 46 void
 47 resuse_start (resp) //resuseは、resource use startの略と思われる。
 48      RESUSE *resp;
 49 {
 50 #if HAVE_WAIT3
 51   gettimeofday (&resp->start, (struct timezone *) 0);
 52 #else
 53   long value;
 54   struct tms tms;
 55
 56   value = times (&tms); // man によると返り値は過去のある時点からのtick
 57   resp->start.tv_sec = value / HZ; // HZ は、CPUクロックか? 確証は得られてない
 58   resp->start.tv_usec = value % HZ * (1000000 / HZ);
 59 #endif
 60 }
現在のクロックカウント(と言っていいのか?)をHZで割って時刻をresp->start.tvに保持する

-resuse.c: resuse_end
117   resp->elapsed.tv_sec -= resp->start.tv_sec; // real time (sec)?
124   resp->elapsed.tv_usec -= resp->start.tv_usec; // real time (micro sec)?
コマンド実行後に省略したが同様にCPU時刻を取得して実行前の時刻を引いている。=> 正味実行にかかった時間(real time)を算出。


struct tmsとは何か?
struct tms -> linux/times.h
 6 struct tms {
  7         __kernel_clock_t tms_utime; // user time
  8         __kernel_clock_t tms_stime; // system time
  9         __kernel_clock_t tms_cutime; // child process user time
 10         __kernel_clock_t tms_cstime; // child process system time
 11 };

__kernel_clock_t -> linux/types.h
 79 typedef __kernel_clock_t        clock_t;


-time.c : summarize
320 static void
321 summarize (fp, fmt, command, resp)
322      FILE *fp;
323      const char *fmt;
324      const char **command;
325      RESUSE *resp;
326 {


-kernel/sys.c 912 void do_sys_times(struct tms *tms)
 921         tms->tms_utime = cputime_to_clock_t(tgutime);
 922         tms->tms_stime = cputime_to_clock_t(tgstime);
 923         tms->tms_cutime = cputime_to_clock_t(cutime);
 924         tms->tms_cstime = cputime_to_clock_t(cstime);


thread_group_timesとは
kernel/sched.c

3398 void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
3399 {
3400         struct task_cputime cputime;
3401        
3402         thread_group_cputime(p, &cputime);
3403
3404         *ut = cputime.utime;
3405         *st = cputime.stime;
3406 }


kernel/posix_cpu_timers.c

234 void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
 235 {
 236         struct sighand_struct *sighand;
 237         struct signal_struct *sig;
 238         struct task_struct *t;
 239
 240         *times = INIT_CPUTIME;
 241
 242         rcu_read_lock();
 243         sighand = rcu_dereference(tsk->sighand);
 244         if (!sighand)
 245                 goto out;
 246
 247         sig = tsk->signal;
 248
 249         t = tsk;
 250         do {
 251                 times->utime = cputime_add(times->utime, t->utime);
 252                 times->stime = cputime_add(times->stime, t->stime);
 253                 times->sum_exec_runtime += t->se.sum_exec_runtime;
 254
 255                 t = next_thread(t);
 256         } while (t != tsk);
 257
 258         times->utime = cputime_add(times->utime, sig->utime);
 259         times->stime = cputime_add(times->stime, sig->stime);
 260         times->sum_exec_runtime += sig->sum_sched_runtime;
 261 out:
 262         rcu_read_unlock();
 263 }


include/asm-generic/cputime.h
12 #define cputime_add(__a, __b)           ((__a) +  (__b))

next_thread(t);とは
include/linux/sched.h

2177 static inline struct task_struct *next_thread(const struct task_struct *p)
2178 {              
2179         return list_entry_rcu(p->thread_group.next,
2180                               struct task_struct, thread_group);
2181 }

thread_group.nextとは、
include/linux/sched.hのtask_structのメンバー
1285         struct list_head thread_group;

list_headとは、
include/linux/list.h

 41 struct list_head {
 42         struct list_head *next, *prev;          
 43 };


list_entry_rcuとは?
include/linux/rculist.h

210 #define list_entry_rcu(ptr, type, member) \
211         container_of(rcu_dereference_raw(ptr), type, member)




spin_lock_irq のirqとは?
include/linux/spinlock.h

307 static inline void spin_lock_irq(spinlock_t *lock)
308 {      
309         raw_spin_lock_irq(&lock->rlock);
310 }
include/linux/spinlock.h
220 #define raw_spin_lock_irq(lock)         _raw_spin_lock_irq(lock)
include/linux/spinlock-api_up.h
59 #define _raw_spin_lock_irq(lock)                __LOCK_IRQ(lock)


spin_local_irqに渡しているcurrent_sighand_siglockとは?


[conclusion]
utimeとstimeは、とりあえず全てのスレッド分足してそうだというとこまでは行ったがかなり消化不足気味

[気になるキーワード]
Hyper Threading
SMT (Simultaneous Multi Threading) 同時マルチスレッディング
SMP (Symmetric Multi Processing) 対象型マルチプロセシング

[Visual Studio C++] PEバイナリのエクスポートされたシンボル

PEバイナリのエクスポートされたシンボル名を確認する

漢は黙ってバイナリエディタといきたいとこだけど
今回は、MSさんのツール(dumpbin)を使います。

このdumpbinは、Visual Studioを使うと [Install Direcotry]\VC\bin にインストールされます。

ここは、PATHが通ってないし、dumpbinが使うライブラリがあるPATHがサーチパスに含まれてないため、dumpbin.exeと同一ディレクトリにあるバッチファイル vcvars32.bat を実行する必要があります。


そして、

dumpbin /EXPORT input.dll

とすることでシンボル名を確認することができる。

[c言語] Windows と Linux の共有ライブラリ

分けあってWindows向けの共有ライブラリ(dll) と Linux向けの共有ライブラリ(so) を
一つのC言語のソースで用意する必要が生じだ。

後にも先にもこれ一回限りな気がするけど一応メモ
検証環境は、

Windows 7 64bit版 C Compiler: gcc ライブラリを使う言語とコンパイラ Delphi XE2
Linux (RHEL) C Compiler: gcc ライブラリを使う言語とコンパイラ Fortran 90  pgfortran



まずは、ヘッダファイルとソース

add.h

#ifndef ADD_H
#define ADD_H

int add_(int *a, int *b)

int devide_(float *a, float *b, float *c)
#endif


add.c
#include<stdio.h>


int add_(int *a, int *b){
    int c;

  c = *a + *b;
  return c;
}

int devide_(float *a, float *b, float *c){

    *c = *a / *b;

    return 0;
}

ポイントは、引数がすべて参照渡しになっている点です。 Fortranが参照渡しがデフォルトなためです。 また、関数名がアンダースコアで終わっているのは、また後で。。。

お次は、コンパイル
まずは、Windowsで

gcc -shared -m32 -o add.dll add.c

-m32 は、32bi tPEバイナリを出力するためのオプションでdllを使う、アプリケーション(exe)が32bitであるため。

次に、Linuxで
gcc -fPIC -shared -o libadd.so add.c

-fPICは、位置独立コード(Position Independent Code)というメモリのどのアドレにもロード可能にするためのオプションです。


そして、使う側。
まずは、Delphi

unit use;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm6 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

  TAdd = function(a : PInteger; b : PInteger) : integer ; stdcall;
  TDevide = function(a : PSingle; b : PSingle; c : PSingle) : integer ; stdcall;

var
  Form6: TForm6;

implementation

{$R *.dfm}

procedure TForm6.Button1Click(Sender: TObject);
var
 ret : integer;
 a,b : integer;
 c,d,e   : single;
 Handle : THandle;
 Add    : TAdd;
 Devide : TDevide;
begin
 a := 4;
 b := 2;
 c := 4.0;
 d := 2.0;
 Handle := LoadLibrary('add.dll');
 if Handle <> 0 then
 begin
   @Add := GetProcAddress(Handle, 'add_');
   if @Add <> nil then
   begin
     ret := add(@a, @b);
     ShowMessage(IntToStr(ret));
   end;
   @Devide := GetProcAddress(Handle, 'devide_');
   if @Devide <> nil then
   begin
     ret := devide(@c, @d, @e);
     ShowMessage(FloatToStr(e));
   end;
   FreeLibrary(Handle);
 end;
end;

end.

関数をtypedefして、GetProcAddress にて関数のあるアドレスを取得する。

次は、Linux上のFortran
interface節を記述したインクルードファイルを作成

addf.h
      interface
        integer function add(a,b)
          integer a,b
        end function add

        integer function devide(a,b,c)
          real  a,b,c
        end function devide

      end interface

次にFortranのソース本体
       program test
       include 'addf.h'
       integer c,d
       real e,f,g
       c=4
       d=2
       e=4.0 
       f=2.0
       d = add(c,d)
       i = devide(e,f,g)
       write(*,*) d,g,i
       end program test

そしてコンパイル
pgfortran -I./include -L./lib -ladd src/use.f

-l で使用するライブラリを指定します。
また、Fortranの場合、関数名は、アンダースコアがついたシンボルを探すのでCの関数名には、アンダースコアをつける必要があります。


2013年5月2日木曜日

[CentOS] コマンドラインでWindowsなホストの共有ディレクトリをマウント

Windows独自プロトコルであるSMB (Server Message Block)を拡張仕様公開した、CIFS を実装してGPL v3 にて公開しているのがSamba ということらしいのですが

今回は、mountコマンドにてWindowsなホストで共有でしているディレクトリをCentOS release 6.4 にてマウントしてみます。

まず、必要パッケージのインストール

yum -y install samba-client
yum -y install cifs-utils


必要に応じてマウントポイントの作成

mkdir -p /mnt/winshare

そして、マウント

mount -t cifs //192.168.100.2/Users/hoge /mnt/winshare -o username=hoge

実行するとWindows上の共有しているディレクトリへのアクセス権のあるWindowsドメインのユーザーアカウントのパスワードを聞かれるので入力する。

192.168.200.2は、WindowsホストのIPアドレス

2013年4月29日月曜日

[CentOS] Building Bewulf type PC cluster

Bewulf型PCクラスタを構築してみる。
目標は、
 「MPIライブラリを使ったサンプルプログラムを複数ノードで実行する」

今回構築するクラスタの概要は、
*ヘッドノード、スレーブノード2ノードの計3ノード
*すべてのノードは、CentOS release 6.4 minimal
*ヘッドノードは、/home のみをNFSにて共有する(ディスクレスに挑戦したかったけどまた今度

ネットワークは、下図の様になる。
192.168.200.0/24がクラスタ専用のネットワークです。

各ノードのスペックは、

node name      CPU                       RAM         HDD
bwhead       amd64 (1 core)*1     2 Gbyte       50Gbyte x 2*2
bwslv01      amd64  (1 core)     1 Gbyte       50 GByte
bqslv02      amd64  (1 core)     1Gbyte        50 GByte

*1 型名になっていないのは、今回構築したノードすべてが仮想マシンだからです。
*2 /home 用に1台、/用に1台



-目次-

[0] HeadノードへのOSのインストール
一番上の項目を選択
イメージをマウントしてますが、メディアテスト

Testを選択

OK



Continueを選択

OK

Next

Engilish

キーボードレイアウトの選択英字配列キーボードを使ってます。

Basic strage device


Yesを選択

ホスト名 ここでは、間違っていたので後でbwheadに修正しました。

タイムゾーン Tokyo/Asia


root のパスワード

パーティション構成を決めます

今回は、このように切ることにしました

Formatを押下

Write changes to diskを押下

Nextを押下


インストール中です

インストール完了 再起動します

再起動後 ログイン状況


[1] Head ノードの設定

A) ネットワークインターフェースの設定
前述のネットワーク構成図に沿って設定します。
/etc/sysconfig/network-scripts/ifcfg-eth0
ONBOOT=yes
BOOTPROTO=dhcp

/etc/sysconfig/network-scripts/ifcfg-eth1
ONBOOT=yes
BOOTPROTO=static
IPPADDR=192.168.200.1
NETMASK=255.255.255.0


B) /etc/hosts の編集
以下を追加
192.168.200.1 bwhead
192.168.200.2 bwslv01
192.168.200.3 beslv02
上記の編集を反映させるためにネットワークサービスを再始動
/etc/init.d/networking restart

C) DHCPサーバーのインストール
slaveノードへのOSのインストールは、物理マシンでの構築の演習としてPXEによるネットワークブートとします。ネットワークブートでは、ブートローダーの場所等の情報を配布するのにDHCPを用います。そこでDHCPサーバーを構築します。

yum list dhcp
でパッケージを検索

yum install dhcp
そして、設定ファイルを作成
---- /etc/dhcp/dhcpd.conf ------

#
# DHCP Server Configuration file.
#   see /usr/share/doc/dhcp*/dhcpd.conf.sample
#   see 'man 5 dhcpd.conf'
#

DHCPDARGS=eth1;

# network boot setttings
allow booting;
allow bootp;
option option-128 code 128 = string;
option option-129 code 129 = text;
next-server 192.168.200.1;
filename "pxelinux.0";


subnet 192.168.200.0 netmask 255.255.255.0{

  # default gateway
  option routers                192.168.200.1;
  option subnet-mask            255.255.255.0;

  option domain-name-servers    192.168.100.1;

  range 192.168.200.100 192.168.200.254;
  default-lease-time 21600;
  max-lease-time 43200;

  host bwslv01{
    hardware ethernet 08:00:27:9C:25:55;
    option host-name "bwslv01";
    fixed-address 192.168.200.2;
  }
 
  host bwslv02{
    hardware ethernet 08:00:27:29:4E:37;
    option host-name "bwslv02";
    fixed-address 192.168.200.3;
  }

   
}

------------------------------------



設定ファイルの構文チェック
service dhcpd configtest
service dhcpd start
chkconfig dhcpd on

dhcpの使うポートを開けておく
iptables  -I INPUT -i eth1 -p udp --dport 67:68 --sport 67:68 -j ACCEPT
再起動時に設定が無効にならないように
/etc/init.d/iptables save
ファイヤーウォールの再起動
/etc/init.d/iptables restart


D) tftpサーバーのインストール
ネットワークブートにおいてブートローダ等を配布するのに必要

yum install tftp tftp-server
/etc/xinetd.d/tfptd
chkconfig xinetd on
service xnetd start

chkconfig tftp on

E) slave ネットワークブートのための準備
syslinuxをインストールします。
yum install syslinux

PXEブートにブートローダ関係の必要なファイルをtftpの公開ディレクトリにコピーします。
cp /usr/lib/syslinux/pxelinux.0 /var/lib/tftpboot
cp /usr/lib/syslinux/menu.c32 /var/lib/tftpboot
cp /usr/lib/syslinux/memdisk /var/lib/tftpboot
cp /usr/lib/syslinux/mboot.c32 /var/lib/tftpboot
cp /usr/lib/syslinux/chain.c32 /var/lib/tftpboot

OS関係の必要なファイルをtftpサーバーの公開ディレクトリに取ってきます。
yum install wget
mkdir -p /tftpboot/images/centos/x86_64/6.4
cd /var/lib/tftpboot/images/centos/
wget http://linux.mirrors.es.net/centos/6.4/os/x86_64/images/pxeboot/initrd.img
wget http://linux.mirrors.es.net/centos/6.4/os/x86_64/images/pxeboot/vmlinuz

ブートローダメニューの設定ファイルを作成
---/var/lib/tftpboot/pxelinux.cfg/default---

default menu.c32
prompt 0
timeout 300
INTIMEOUT local

MENU TITLE PXE Menu

LABEL local
MENU LABEL Boot from local hard disk drive
LOCALBOOT 0

LABEL CentOS 6.4 x86_64
MENU LABEL CentOS 6.4 x86_64
KERNEL images/centos/6.4/x86_64/vmlinuz
APPEND load initrd=images/centos/6.4/x86_64/initrd.img devfs=nomount


--------------------------------------



tftp(udp 69番ポート)を開ける
iptables -A INPUT -m state --state NEW -i eth0 -p udp --dport 69 -j ACCEPT
再起動時に設定が無効にならないように
/etc/init.d/iptables save
ファイヤーウォールの再起動
/etc/init.d/iptables restart

フォワーディングを有効にする
-- /etc/sysctl.conf--
# Controls IP packet forwarding
net.ipv4.ip_forward = 1   # 0 から 1に変更
----------------------


[2] slavve ノードのOSインストール
仮想マシンを起動したら即座にF12キーを押下する

PXEブートするために「l」キーを押下する

予め行った設定が適切に行われていれば
tftpサーバーからブートロードがDLされてメニューが表示される
CentOSを選択して、Enterを押下
インストール中に用いる言語の選択

キーボードレイアウトの選択

OSインストーラーのメディア種別を選択。セキュリティ的には、
あまり宜しくないけどHTTPで取ってきます。

ネットワーク設定
IPv4は、DHCPにします。

NIC設定中

インストーラーイメージ取得中

これ以降は、Headノードと同じGUIなインストーラーが起動しての同じインストールとなる。



[3] ssh でのhead から slave へのパスワード無しログイン
MPIライブラリのデータの移動、設定ファイルの配布のための仕組みを構築します。
よくr系コマンドが用いられますが、自分の環境では、rootでのパスワード無しログインが
できるようにすることを断念したため、sshを用います。

A) slave ノードへssh-server のインストール
yum install openssh-server
scpを使うため
yum install openssh-client


/etc/ssh/sshd_configの以下のコメントをはずす
#PermitRootLogin yes -> PermitRootLogin yes

chkconfig ssh on
service sshd start

試しにrootで全てのslaveノードにログインしてみる

ssh root@192.168.200.n # n は、整数
ログインしたまま後の作業の準備
cd $HOME
mkdir .ssh


B) head ノードでの作業

公開鍵生成

ssh-keygen -b 1024 -t rsa
鍵のパスフレーズは空にしておく

公開鍵を全てのslaveノードに配布しておく。
scp ~/.ssh/id_rsa.pub root@192.168.200.n:.ssh/authorized_keys

クラスタは、外からの開始される接続を許可しないネットワーク内で運用するのでとりあえずSElinuxは無効化しておく。
setenforce 0
そして、起動後も無効になるように/etc/selinux/configのSELINUXTYPEを下記のようにdisabledに変更しておく。
SELINUXTYPE=diabled


C)シェルスクリプトの作成

各ノードに同様の実行するためのシェルスクリプトを用意( rshでも実現可能だが自分の環境では、rootでの実行がPermission Denied ど言われで実現できなかった


----${HOME}/utils/rssh.sh-----

#!/bin/bash
BEGIN_ADDR=2
END_ADDR=3
ADDR_PREFIX="192.168.200."

for i in `seq $BEGIN_ADDR $END_ADDR`
do
  DST_ADDR="$ADDR_PREFIX$i"
  echo "Processing for $DST_ADDR"

ssh $DST_ADDR<<EOF
$*
EOF

done

---------------------------
chmod 744 ${HOME}/utils/rssh.sh

各ノードにファイルコピーするためのコマンド
---${HOME}/utils/rsscp.sh---

#!/bin/bash
SRC_FILE=$1
DST_PATH=$2

BEGIN_ADDR=2
END_ADDR=3

ADDR_PREFIX="192.168.200."

for i in `seq $BEGIN_ADDR $END_ADDR`
do
  DST_ADDR="$ADDR_PREFIX$i"
  echo "Copying $SRC_FILE -> $DST_ADDR:$DST_PATH"

scp $SRC_FILE $DST_ADDR:$DST_PATH

done

--------------------------

D) /etc/hosts の配布

/etc/hosts を作成して
 ${HOME}/utils/rsscp.sh /etc/hosts /etc/hosts


[4] NIS を用いたアカウント一元管理

A) サーバーの構築

アカウントを一括管理するためにNISサーバーを構築する

まずは、サーバーのインストール
yum install ypserv

ドメインの設定 このドメインは、DNSとは関係がない
ypdomainname clnet

/etc/sysconfig/network に 先ほど設定したNISドメインを追加
NISDOMAIN = clnet

/var/yp/Makefile の編集(下記がオリジナルのファイルとの差分)
-----差分-----------------------

*** Makefile.org 2013-04-27 17:41:09.642037547 +0900
--- Makefile 2013-04-27 17:42:41.594036564 +0900
***************
*** 39,49 ****
 
  # Should we merge the passwd file with the shadow file ?
  # MERGE_PASSWD=true|false
! MERGE_PASSWD=true
 
  # Should we merge the group file with the gshadow file ?
  # MERGE_GROUP=true|false
! MERGE_GROUP=true
 
  # These are commands which this Makefile needs to properly rebuild the
  # NIS databases. Don't change these unless you have a good reason.
--- 39,49 ----
 
  # Should we merge the passwd file with the shadow file ?
  # MERGE_PASSWD=true|false
! MERGE_PASSWD=false
 
  # Should we merge the group file with the gshadow file ?
  # MERGE_GROUP=true|false
! MERGE_GROUP=false
 
  # These are commands which this Makefile needs to properly rebuild the
  # NIS databases. Don't change these unless you have a good reason.
***************
*** 114,120 ****
  # If you don't want some of these maps built, feel free to comment
  # them out from this list.
 
! all:  passwd group hosts rpc services netid protocols mail \
  # netgrp shadow publickey networks ethers bootparams printcap \
  # amd.home auto.master auto.home auto.local passwd.adjunct \
  # timezone locale netmasks
--- 114,120 ----
  # If you don't want some of these maps built, feel free to comment
  # them out from this list.
 
! all:  passwd shadow group hosts rpc services netid protocols mail \
  # netgrp shadow publickey networks ethers bootparams printcap \
  # amd.home auto.master auto.home auto.local passwd.adjunct \
  # timezone locale netmasks

--------------------------------


このままだとすべてのホストからNIS情報を引き出すことができるようになっているので
NIS情報を引き出せるホストを限定するために /var/yp/securenets を作成して
以下を書き込みます。
255.255.255.0 192.168.200.0


これで指定したネットワークに属するホストだけがNIS情報を引き出せるようになりました。
ここでサーバーデーモンの起動
/etc/rc.d/init.d/ypserv start
/etc/rc.d/init.d/yppasswdd start

そして、起動時に自動でデーモンが走るように以下を実行
chkconfig ypserv on
chkconfig yppasswdd on

/usr/lib64/yp/ypinit -m を実行
NISサーバーの情報を確認される。今回は、サーバーは1台体制(冗長化無し)なのでNISDOMAINで設定した内容が表示されていればおk

B) ファイヤーウォールの設定
portmapper が使う tcp と udp 111番ポートへの通信を受け入れるようにしておく。


C ) クライアントの準備 (サーバーマシンでも実行する)
./rssh.sh  ' echo "NISDOMAIN = clnet" >> /etc/sysconfig/network '
./rssh.sh "sed -ei 's/\(USENIS=\)no/\1yes/' /etc/sysconfig/authconfig "
./rssh.sh 'echo "domain clnet server bwhead" > /etc/yp.conf'

slaveノード用のNS設定ファイルを作成して配布する。
mkdir tmp
cd tmp
cp /etc/nsswitch.conf tmp.conf
スレーブ用設定ファルの変更。以下がオリジナルのファイルとの差分
------差分----------

*** /etc/nsswitch.conf 2013-04-29 15:43:35.280253996 +0900
--- tmp.conf 2013-05-06 22:59:03.979813909 +0900
***************
*** 30,38 ****
  #shadow:    db files nisplus nis
  #group:     db files nisplus nis
 
! passwd:     files nis
! shadow:     files nis
! group:      files nis
 
  #hosts:     db files nisplus nis dns
  hosts:      files dns nis
--- 30,38 ----
  #shadow:    db files nisplus nis
  #group:     db files nisplus nis
 
! passwd:     nis files
! shadow:     nis files
! group:      nis files
 
  #hosts:     db files nisplus nis dns
  hosts:      files dns nis

--------------------
cd
./rscp.sh ./tmp/tmp.conf /etc/nsswitch.conf

ypbind をインストールする
./rssh.sh 'yum -y install rpcbind'
./rssh.sh '/etc/rc.d/init.d/rpcbind start'
./rssh.sh 'chkconfig rpcbind on'

./rssh.sh 'yum -y install ypbind'
./rssh.sh '/etc/rc.d/init.d/ypbind start'
./rssh.sh 'chkconfig ypbind on'


D) ユーザーの追加 (適宜)
NISサーバーにて
useradd newuser_name
passwd newuser_name

以上で通常通りユーザーを追加した後

cd /var/yp
make

でNIS DBに追加したユーザーの情報を追加する。
これでもログイン出来ない場合は、まずクライアントマシンで
ypcat passwd して追加したユーザーの情報が反映されれているかチェック。

追加されているにもかかわらずログイン出来ない場合は、
/etc/ypserv.conf中の
files: 30

files: 0
に変更してキャッシュを無効にする。


[5] NFS の構築

すべてのノードでホームディレクトリを共有できるようにする。

A) サーバーの構築

yum -y install nfs-utils

共有するディレクトリに関する設定を行う /etc/exports に以下を追加

/home 192.168.200.0/24(rw,sync,no_root_squash,no_all_squash)

/home … 共有するディレクトリの指定
192.168.200.00/24 … 共有を許すネットワーク
sync … 遅延書き込みをしない
no_root_squash … root の特権を行こうにする
no_all_squash … そのままの権限でアクセスさせる

/etc/idampd.conf にドメインの設定をする。デフォルトでは、「Domain = 」を含む行がコメントアウトされているので有効にしてドメインを記述する。

Domain = clnet


起動していないデーモンを起動しておく
/etc/rc.d/init.d/rpcbind start
/etc/rc.d/init.d/nfslock start
/etc/rc.d/init.d/nfs start

起動時にデーモンが自動で起動するようにしておく

chkconfig rpcbind on
chkconfig nfslock on
chkconfig nfs on


B) クライアントの準備

サーバーマシンからシェルスクリプトを用いて実行する

./rssh.sh 'yum -y install nfs-utils'

先ほど編集したNFSサーバーの /etc/idamp


./rssh.sh '/etc/rc.d/init.d/rpcbind start'
./rssh.sh '/etc/rc,d/init.d/nfslock start'
./rssh.sh '/etc/rc.d/init.d/netfs start'

./rssh..sh 'chkconfig rpcbind on'
./rssh.sh 'chkconfig nfslock on'
../rssh.sh 'chkconfig netfs on'


ここからは、各ノードに直接ログインして操作する
まずは、サーバーのパーティションをマウントできるかをテスト


mount -t nfs bwhead:/home /home

df -h

でマウントされたかどうかを確認する。

次に起動時に自動でマウントされるように/etc/fstab を変更
以下の行を追記
bwhead:/home /home nfs bg,intr 0 0

bg… NFSでのマウントが失敗した時にバックグランドで試行を繰り返す。
intr … 停止しているプロセスをkillするために、割り込みを可能にする。
0 … dump頻度
0 … fchkパスのフィールド

さらにインストール時に切った/home のパーティションをマウントしないようにコメントアウトしておく。
これ以上ができたNFSクライアントマシンを再起動して無事にマウントされるかを確認しておく。


[6] OpenMPI のインストール(headノード含めすべてのノードで)
その前にgcc とg++ ,makeのインストール

yum -y install gcc
yum -y install gcc-c++
yum -y install make

今回は、OpenMPI Ver.1.6.4 を用いる。
wget http://www.open-mpi.org/software/ompi/v1.6/downloads/openmpi-1.6.4.tar.gz
cd openmpi-1.6.4
./configure --prefix=/usr/local
make all # 複数コアある場合は make -j num_proc all で並列コンパイルできるらしい

[7] サンプルプログラムの実行

実行用専用ユーザーをNISサーバーにて作る
useradd cltest
passwd cltest
NIS DBへの反映
cd /var/yp ; make

ヘッドノードにてログアウトしてcltestでログインする
以下のソースを作成
-----main.c------------

#include <stdio.h>
#include <mpi.h>

int main(int argc, char **argv){
int rank, size, namelen;
char name[256];

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Get_processor_name(name, &namelen);
sleep(5);
printf("This is %d of %d on %s\n", rank, size, name);
MPI_Finalize();
return 0;
}

----------------------

mpicc main.c
でコンパイル。


実行前にライブラリサーチPATHをbashrcに追加
export LD_LIBRARY_PATH=/usr/local
source .bashrc


そして、root権限を得て/usr/local/etc/openmpi-default-hostfile (headノード)
にどのユーザーのジョブでも常に実行させたシステム共通の計算ノードを追記する。
以下例
bwhead
bwslv01
bwslv02

本来なら、ヘッドノードは、ジョブ実行のみで計算は行わないがホストPCのリソースがそんなに潤沢ではないためヘッドノードも追加した。


mpirun -np 3 a,out

これで下記の様に各ノードでの出力が表示されればクラスタ構築一応完了。
---実行結果-----

This is 0 of 3 on bwhead.clnet
This is 1 of 3 on bwslv01
This is 2 of 3 on bwslv02

----------------



[7]参考
http://kuni255.blogspot.jp/2013/04/iptables.html