Gauche-FUSEでOutputzファイルシステム
シェルでの操作も Outputz に入れたいが良い方法はないかな。キーロガーまで行くとやりすぎ感がある。ヒストリを定期的に POST かな。
cd, ls しすぎ問題を把握したい。
http://d.hatena.ne.jp/higepon/20081125/1227598921
- 使い方
$ mkdir /tmp/fs
$ ./outputz.scm -m="/tmp/fs" -k=**SECRET_KEY**
$ cd /tmp/fs楽しんだ後で...
$ fusermount -u /tmp/fs
Outputzファイルシステム上では、以下をカウントします。
- readdirの回数
- readしたバイト量
- writeしたバイト量
そして、dfすると、記録したカウントをOutputzに送信します。
$ df /tmp/fs
unique: 114, opcode: STATFS (17), nodeid: 1, insize: 40
200: ok uri=http://teruaki-desktop/write/home/teruaki/c size=42
200: ok uri=http://teruaki-desktop/read/home/teruaki/a size=42
200: ok uri=http://teruaki-desktop/readdir/home/teruaki size=3
それ以外は通常どおり使えます。
(11/28 11:56追記ここから)
実行してみます。
/home/teruaki% mkdir /tmp/fs
/home/teruaki% ./outputz.scm -m=/tmp/fs -k=****
unique: 1, opcode: INIT (26), nodeid: 0, insize: 56
INIT: 7.9
flags=0x0000000b
max_readahead=0x00020000
INIT: 7.8
flags=0x00000001
max_readahead=0x00020000
max_write=0x00020000
unique: 1, error: 0 (Success), outsize: 40
unique: 2, opcode: LOOKUP (1), nodeid: 1, insize: 47
LOOKUP /.Trash
unique: 2, error: -2 (No such file or directory), outsize: 16
unique: 3, opcode: LOOKUP (1), nodeid: 1, insize: 52
LOOKUP /.Trash-1000
unique: 3, error: -2 (No such file or directory), outsize: 16
unique: 4, opcode: LOOKUP (1), nodeid: 1, insize: 47
LOOKUP /.Trash
unique: 4, error: -2 (No such file or directory), outsize: 16
unique: 5, opcode: LOOKUP (1), nodeid: 1, insize: 52
LOOKUP /.Trash-1000
unique: 5, error: -2 (No such file or directory), outsize: 16
FUSEのデバッグプリントです。
別窓を開いて/tmp/fs/home/teruakiにアクセスしてみます。
@別窓
/home/teruaki% cd /tmp/fs/home/teruaki
/tmp/fs/home/teruaki% ls
ACCESS / 01
unique: 6, error: 0 (Success), outsize: 16
unique: 7, opcode: LOOKUP (1), nodeid: 1, insize: 45
LOOKUP /home
NODEID: 2
unique: 7, error: 0 (Success), outsize: 136
unique: 8, opcode: ACCESS (34), nodeid: 2, insize: 48
ACCESS /home 01
unique: 8, error: 0 (Success), outsize: 16
unique: 9, opcode: LOOKUP (1), nodeid: 2, insize: 48
LOOKUP /home/teruaki
NODEID: 3
unique: 9, error: 0 (Success), outsize: 136
unique: 10, opcode: ACCESS (34), nodeid: 3, insize: 48
ACCESS /home/teruaki 01
unique: 10, error: 0 (Success), outsize: 16
(中略)
unique: 36, opcode: READDIR (28), nodeid: 3, insize: 80
unique: 36, error: 0 (Success), outsize: 16
unique: 37, opcode: RELEASEDIR (29), nodeid: 3, insize: 64
unique: 37, error: 0 (Success), outsize: 16
デバッグプリントの最後に、ls したときのREADDIRがあります。
OutputzファイルシステムはREADDIRの回数をカウントしています。
df するとOutputzに送信します。
@別窓
/tmp/fs/home/teruaki% df
Filesystem サイズ 使用 残り 使用% マウント位置
/dev/sda2 8.0G 4.5G 3.1G 60% /
...
gvfs-fuse-daemon 8.0G 4.5G 3.1G 60% /home/teruaki/.gvfs
/dev/fuse 8.0G 4.5G 3.1G 60% /tmp/fs
するとFUSEの方では
unique: 38, opcode: STATFS (17), nodeid: 1, insize: 40
200: ok uri=http://teruaki-desktop/readdir/home/teruaki size=1
unique: 38, error: 0 (Success), outsize: 96
とデバッグプリントしていて、送信が200: okで成功しているのがわかります。
(注意)
FUSEをシングルスレッドで動かしているので、ひとつコマンドが刺さると、ほかのコマンドが処理できず、全体が止まったように見えることがあります。
(11/28 11:56追記ここまで)
#!/usr/bin/env gosh (use rfc.http) (use rfc.uri) (use gauche.parseopt) (use fuse) (define secret-key "") (define ht (make-hash-table 'string=?)) (define (ht-inc! key . opt) (let ((v (get-optional opt #f))) (hash-table-update! ht key (cut + (if v v 1) <>) 0))) (define (submit-outputz path size) (define hostname (sys-gethostname)) (define (make-uri path) (string-join `("http:/" ,hostname ,path) "/")) (receive (status header body) (http-post "outputz.com" "/api/post" (apply format "uri=~a&size=~d&key=~a" (map uri-encode-string (list (make-uri path) (x->string size) secret-key)))) (format #t "~a: ~a uri=~a size=~a\n" status body (make-uri path) size))) (define (outputz-statfs path) (hash-table-for-each ht submit-outputz) (hash-table-clear! ht) (sys-statvfs path)) (define (outputz-readdir path fuse-info) (ht-inc! (string-append "readdir" path)) (sys-readdir path)) (define (outputz-mknod path mode rdev) (define st (make <sys-stat>)) (sys-stat->mode-set! st mode) (case (slot-ref st 'type) ('regular (close-output-port (open-output-file path))) ('fifo (sys-mkfifo path mode)) (else ;;please use the "mknod" external command. (error <system-error> :errno ENOENT)))) (define (outputz-open path file-info) (close-input-port (open-input-file path))) (define (outputz-read path outp size offset file-info) (call-with-input-file path (lambda (in) (port-seek in offset) (rlet1 v (copy-port in outp) (ht-inc! (string-append "read" path) v))))) (define (outputz-write path inp size offset fuse-info) (call-with-output-file path (lambda (out) (port-seek out offset) (rlet1 v (copy-port inp out) (ht-inc! (string-append "write" path) v))) :if-exists :overwrite)) (define (main args) (let-args (cdr args) ((key "k|key=s") (mountpoint "m|mount=s" #f) . rest) (unless mountpoint (print "usage: -k=YOUR_SECRET_KEY -m=MOUNT_POINT") (exit 1)) (set! secret-key key) (start-fuse mountpoint :getattr sys-lstat :access sys-access :readlink sys-readlink :mkdir sys-mkdir :symlink sys-symlink :unlink sys-unlink :rmdir sys-rmdir :rename sys-rename :link sys-link :chmod sys-chmod :chown sys-chown :truncate sys-truncate :utimens sys-utime :statfs outputz-statfs :readdir outputz-readdir :mknod outputz-mknod :open outputz-open :read outputz-read :write outputz-write)))