Segmentation Faultぐ

Segmentation Fault

コアダンプの数だけ強くなれるよ。

Linuxのnamespaceでネットワークを区切って遊ぶ

Linuxのnamaspace(名前空間)で遊んでみます。

Dockerとかコンテナを実現する技術で使われるアレですね。

お遊び内容



まず、下図のネットワーク構成を作ります。

f:id:segmentation-fault:20180121153248p:plain


・eth1,eth2は内部ネットワーク
・vlan100,vlan200はVLANタグ付きのインタフェース
・veth1, veth2はnamespace間をつなぐインタフェース
・br1,br2はブリッジ



VLAN単位でネットワークを区切って通信ができるのか確認してみます。
ルーター、L3スイッチのVRFみたいなものですね。

vlan100,vlan200はネットワークが違うのでIPアドレスが同じでも各々で通信が可能なはずです。


各種設定


まず、VM1,VM2を作成します。(ここではともにCentOS 7です)

内部ネットワークのインタフェースはプロミスキャスモードをすべて許可にしてから起動します。
(許可しないとnamespace側のMACアドレスが宛先MACになっているフレームを破棄してしまうため)

f:id:segmentation-fault:20180121154012p:plain


以下、各VMの設定です。

◆VM1

内部ネットワークのインタフェース名を構成図のeth1に合わせます。

[user@localhost ~]$ ip link show dev enp0s9
4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether 08:00:27:1d:b8:43 brd ff:ff:ff:ff:ff:ff

[user@localhost ~]$ sudo ip link set dev enp0s9 down
[user@localhost ~]$ sudo ip link set dev enp0s9 name eth1
[user@localhost ~]$ sudo ip link set dev eth1 up

[user@localhost ~]$ ip link show dev eth1
4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether 08:00:27:1d:b8:43 brd ff:ff:ff:ff:ff:


続いてnamespace, 各インタフェースを作成します。

namespaceはip netns add 作ります。
namespace上でコマンドを実行する場合はip netns exec "namespace" "実行したいcommand" となります。

[user@vm1 ~]$ # namespaceの作成
[user@vm1 ~]$ sudo ip netns add ns1                                                      # namespaceの作成
[user@vm1 ~]$ sudo ip link add veth1 type veth peer name eth1 netns ns1                  # namespace間インタフェースの作成

[user@vm1 ~]$ # ブリッジの作成
[user@vm1 ~]$ sudo brctl addbr br1                                                       # ブリッジの作成
[user@vm1 ~]$ sudo brctl addif br1 veth1                                                 # ブリッジにveth1を接続
[user@vm1 ~]$ sudo brctl addif br1 eth1                                                  # ブリッジにeth1を接続

[user@vm1 ~]$ # VLANの作成
[user@vm1 ~]$ sudo ip netns exec ns1 ip link add link eth1 name vlan100 type vlan id 100 # vlan100の作成
[user@vm1 ~]$ sudo ip netns exec ns1 ip addr add 192.168.0.1/24 dev vlan100              # vlan100にIPアドレス設定
[user@vm1 ~]$ sudo ip link add link eth1 name vlan200 type vlan id 200                   # vlan200の作成
[user@vm1 ~]$ sudo ip addr add 192.168.0.1/24 dev vlan200                                # vlan200にIPアドレス設定

[user@vm1 ~]$ # インタフェースのUP
[user@vm1 ~]$ sudo ip link set dev veth1 up                                              # veth1のUP
[user@vm1 ~]$ sudo ip link set dev eth1 up                                               # eth1のUP
[user@vm1 ~]$ sudo ip link set dev br1 up                                                # br1のUP
[user@vm1 ~]$ sudo ip netns exec ns1 ip link set dev eth1 up                             # ns1のeth1をUP
[user@vm1 ~]$ sudo ip netns exec ns1 ip link set dev vlan100 up                          # vlan100のUP
[user@vm1 ~]$ sudo ip link set dev vlan200 up                                            # vlan200のUP


namespaceと各インタフェースが作成されていることを確認します。

[user@vm1 ~]$ ip netns list
ns1
[user@vm1 ~]$
[user@vm1 ~]$ ip addr show
...
       valid_lft forever preferred_lft forever
4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br1 state UP qlen 1000
    link/ether 08:00:27:1d:b8:43 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::bac:439:3aa7:6261/64 scope link
       valid_lft forever preferred_lft forever
6: veth1@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br1 state UP qlen 1000
    link/ether 3a:f0:e6:57:6b:16 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::38f0:e6ff:fe57:6b16/64 scope link
       valid_lft forever preferred_lft forever
7: br1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
    link/ether 08:00:27:1d:b8:43 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::a00:27ff:fe1d:b843/64 scope link
       valid_lft forever preferred_lft forever
8: vlan200@eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
    link/ether 08:00:27:1d:b8:43 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.1/32 scope global vlan200
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe1d:b843/64 scope link
       valid_lft forever preferred_lft forever

[user@vm1 ~]$ sudo ip netns exec ns1 ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth1@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT qlen 1000
    link/ether 26:5a:84:c9:33:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
3: vlan100@eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT qlen 1000
    link/ether 26:5a:84:c9:33:03 brd ff:ff:ff:ff:ff:ff


◆VM2

VM2もVM1と同じように設定します。

[user@vm2 ~]$ # namespaceの作成
[user@vm2 ~]$ sudo ip netns add ns2                                                      # namespaceの作成
[user@vm2 ~]$ sudo ip link add veth2 type veth peer name eth2 netns ns2                  # namespace間インタフェースの作成

[user@vm2 ~]$ # ブリッジの作成
[user@vm2 ~]$ sudo brctl addbr br2                                                       # ブリッジの作成
[user@vm2 ~]$ sudo brctl addif br2 veth2                                                 # ブリッジにveth2を接続
[user@vm2 ~]$ sudo brctl addif br2 eth2                                                  # ブリッジにeth2を接続

[user@vm2 ~]$ # VLANの作成
[user@vm2 ~]$ sudo ip netns exec ns2 ip link add link eth2 name vlan100 type vlan id 100 # vlan100の作成
[user@vm2 ~]$ sudo ip netns exec ns2 ip addr add 192.168.0.2/24 dev vlan100              # vlan100にIPアドレス設定
[user@vm2 ~]$ sudo ip link add link eth2 name vlan200 type vlan id 200                   # vlan200の作成
[user@vm2 ~]$ sudo ip addr add 192.168.0.2/24 dev vlan200                                # vlan200にIPアドレス設定

[user@vm2 ~]$ # インタフェースのUP
[user@vm2 ~]$ sudo ip link set dev veth2 up                                              # veth2のUP
[user@vm2 ~]$ sudo ip link set dev eth2 up                                               # eth2のUP
[user@vm2 ~]$ sudo ip link set dev br2 up                                                # br2のUP
[user@vm2 ~]$ sudo ip netns exec ns2 ip link set dev eth2 up                             # ns2のeth2をUP
[user@vm2 ~]$ sudo ip netns exec ns2 ip link set dev vlan100 up                          # vlan100のUP
[user@vm2 ~]$ sudo ip link set dev vlan200 up                                            # vlan200のUP


疎通確認


vlan200の通信確認

[user@vm1 ~]$ ping 192.168.0.2
[user@vm2 ~]$ sudo tcpdump -i vlan100


f:id:segmentation-fault:20180121154730p:plain



vlan100の通信確認

[user@vm1 ~]$ sudo ip netns exec ns1 ping 192.168.0.2
[user@vm2 ~]$ sudo ip netns exec ns2 tcpdump -i vlan100


f:id:segmentation-fault:20180121154753p:plain



期待通り通信ができることを確認できました。


参考


Technology: VRF & Linux Network Name Space

Linux Network Namespace で遊んでみる | CUBE SUGAR STORAGE

namespace を使ってみる - いますぐ実践! Linuxシステム管理 / Vol.260




proc経由でkernelとやり取りしてみる

procインタフェースを利用してユーザランドのアプリケーションとカーネルでデータをやりとりするサンプルです。

具体的には下記のようにechoでリダイレクトした文字列をカーネルで受信して、catで覗くとリダイレクトした文字列が表示されるような簡単なカーネルモジュールを作ります。開発環境はCentOS7です。

完成イメージ

$ echo "hello" > /proc/example 
$ cat /proc/example 
hello
$


ソースコード

procmod.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/string.h>

static char example[64] = {0};

static ssize_t
example_write(
    struct file *filp,
    const char __user *buff,
    size_t user_len,
    loff_t *offset )
{
    size_t len = 0;

    if (0 != *offset)
        return -EINVAL;

    memset(example, 0, sizeof(example));

    len = user_len > sizeof(example) ? sizeof(example) : user_len;

    memcpy(example, buff, len);
    example[len-1] = '\n';

    printk(KERN_INFO "example: wrote - %s", example);

    return user_len;
}

/* /proc/exampleの内容を表示 */
static int
example_show(
    struct seq_file *p,
    void *v)
{
    seq_printf(p, "%s", example);
    printk(KERN_INFO "example: show - %s", example);
    return 0;
}

/* cat /proc/exampleで実行される */
static int
example_open(
    struct inode *inode,
    struct file *file)
{
    return single_open(file, example_show, NULL);
}

static const struct file_operations proc_example_operations = {
    .owner      = THIS_MODULE,
    .open       = example_open,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = single_release,
    .write      = example_write,
};

/* insmod実行時に呼び出される */
static int proc_example_init(void)
{
    proc_create("example", S_IRUGO | S_IWUGO, NULL, &proc_example_operations);
    printk(KERN_INFO "example: Module loaded, and created /proc/example\n");
    return 0;
}

/* rmmod実行時に呼び出される */
static void proc_example_exit(void)
{
    remove_proc_entry("example", NULL);
    printk(KERN_INFO "example: Module unloaded.\n");
}

module_init(proc_example_init);
module_exit(proc_example_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Example Kernel Module");


Makefile

obj-m := procmod.o

all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean


実行結果

ビルドしてカーネルモジュールをロードします。

$ make
make -C /lib/modules/3.10.0-514.26.2.el7.x86_64/build M=/home/user/driver/proc modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-514.26.2.el7.x86_64'
  CC [M]  /home/user/driver/proc/procmod.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/user/driver/proc/procmod.mod.o
  LD [M]  /home/user/driver/proc/procmod.ko
make[1]: Leaving directory `/usr/src/kernels/3.10.0-514.26.2.el7.x86_64'
$
$ sudo insmod procmod.ko
$ lsmod |grep procmod
procmod                12702  0


f:id:segmentation-fault:20180106230106p:plain


ちゃんとアプリ、カーネル間でデータをやりとりできました。

次回は/dev/にスペシャルファイルを作ってアプリとカーネル間でepoll,ioctlを使った通信を試したいと思います。




さくらVPSでBitZenyを掘ってみる

さくらVPSでBitZenyのプールマイニングに挑戦してみます。まずはお試し1週間です。

はじめに

これまで、さくらVPSの空きリソースを使ってXMR(モネロ)という仮想通貨のプールマイニングをしていましたが、ここ最近の人気上昇を受けてか採掘量が段々と減ってきました(対JPY,BTCの価格もだいぶ上昇しましたし)。所詮空きリソースなのでこのままでも良いのですが、もう少しマイナーな仮想通貨で採掘難易度が低くかつ安定した数量を得られるものの方が面白いかな~と探していたところBitZenyという国産の仮想通貨にたどり着きました。

http://bitzeny.org/

www.segmentation-fault.xyz


全体の流れ

大まかな流れは下記になります。

  1. walletの作成
  2. マイナープールにアカウント作成
  3. ワーカーの作成
  4. マイナーソフトの導入と実行
  5. あとは待つだけ


walletの作成

まずはBitZeny用のwalletを作成します。

https://bitzeny.jp/login

f:id:segmentation-fault:20171222235829p:plain


作成時にニーモニックフレーズを選択します。 とりあえず注意書きにある通り、後で分かるように画面キャプチャとるなどして保管しておけばOK。

f:id:segmentation-fault:20171223000002p:plain


処理を進めるとwalletが出来上がります。
ページの下方にあるwalletのアドレスを後ほど使用します。

f:id:segmentation-fault:20171223000307p:plain


マイナープールにアカウント作成

BitZenyのマイナープールはいくつかありますが、今回アカウントを作成するのは"BitZeny Mining Pool - 大人の自由研究”です。 最初はLA BitZeny Poolにしようかと思ったのですが、最近のBitZeny高騰をうけて人気化した事とLA BitZeny Poolでのマイニングに関する記事が多いためかマイナーが1か所に偏っている状態でした。偏りがあると採掘効率が悪いようですのでこちらにしました。

f:id:segmentation-fault:20171223001341p:plain

BitZeny Mining Pool - 大人の自由研究 - Home



では、右上のメニューからSign Upを選択して新規アカウントを作成していきます。

f:id:segmentation-fault:20171223001441p:plain


アカウントが作成されたら、次はワーカーを作成します。


ワーカの作成

マイニングを行うにはワーカーなるものを作成する必要があります。

左メニューのMy AccountからMy Workerを選択します。

f:id:segmentation-fault:20171223001535p:plain

Add New Workerの所に任意の名前とパスワードを設定しワーカーを追加します。
ワーカーの名前とパスワードはuser, passwordのままでも構いません。

f:id:segmentation-fault:20171223001721p:plain


マイナーソフトの導入と実行

続いてマイナーソフトを採掘を行うマシンにインストールします。

まずは事前準備としてマイナーソフトを使うために必要なソフトを導入します。

$ sudo yum groupinstall "Development Tools"
$ sudo yum install git libcurl-devel python-devel screen rsync


マイナーソフトのソースコードをダウンロードしてビルドします。

$ git clone https://github.com/bitzeny/cpuminer.git cpuminer
$ cd cpuminer
$ ./autogen.sh
$ ./configure CFLAGS="-O3 -march=native -funroll-loops -fomit-frame-pointer"
$ make
$ sudo make install


マイナーソフトが用意できたらマイナープールのホームページの記載の通りにコマンドを実行します。

f:id:segmentation-fault:20171223002302p:plain

ログアウトしても処理を続けて欲しいのでnohupを付けておきます。

$ sudo nohup /usr/local/bin/minerd -a yescrypt -o stratum+tcp://ukkey3.space:3333 -u <ログインアカウント>.<ワーカー名> -p <ワーカーのパスワード> &


コマンドを実行してから数十分ほど待っているとDashBoardのハッシュレート等の採掘状況が表示されるようになります。


結果

ひとまず様子見で5日間でどれくらいマイニング報酬が得られるのか観測してみました。

f:id:segmentation-fault:20171223003002p:plain

大体1日あたり1.8 ZNY ぐらいは得られているでしょうか。
1.0 ZNYの相場が日本円で10円~40円なので20円/日の稼ぎって感じですね。

もちろん今後、価値が上がれば話は変わります(逆もしかり)。


参考

マイナーソフトの導入についてはこちらを参考にさせていただきました。

bombox.net



VBScriptでWordファイルのページ数一覧を作ってみる

ある日、大量のWordファイルで作られた資料の中身を目視確認する必要に迫られました。

複数人で分担して実施するのですがファイル毎にボリューム(ページ数)が異なるためファイル数で割り振ると不公平が発生します。

そこで事前にファイル単位のページ数がわかるといいなぁということでページ数の一覧を生成するスクリプトを作ってみました。

ソースコード


作成したスクリプトはスクリプトを実行したディレクトリ配下にあるWordファイルを検索しページ数を取得して結果をファイル出力します。

Wordファイルのページ数はBuiltinDocumentPropertiesで取ってこれます。

下記を参考にしました。

www.relief.jp


文字コードはSJISなので注意です。(UTF-8だと実行時に日本語を扱っている行で怒られます。)

'
'VBScript File
'Character code is SJIS
'

Option Explicit

Call Main()

'
'@func Main
'@brief メイン関数
'
Sub Main()
  'ファイルシステムオブジェクトの生成
  Dim fso 
  Set fso = CreateObject("Scripting.FileSystemObject")
  
  'カレントDIR配下にあるWordファイルのページ数を取得
  Dim result
  result = GetNumberOfWordFilePageAll(fso, fso.GetFolder("."))
  
  '結果をファイルに出力
  Dim ret
  ret = WriteResultToFile(fso, "result.csv", result)
  
End Sub

'
'@func GetNumberOfWordFilePageAll
'@brief カレントDIRにあるWordファイルのページ数を取得する
'@param[in] dir  ディレクトリパス
'@param[in] fso  ファイルシステムオブジェクト
'
Function GetNumberOfWordFilePageAll(fso, dir)
  
  Dim result
  result= ""
  
  ' カレントDIRにあるwordファイルのページ数を数える
  Dim File
  For Each File in dir.Files
    result= result& GetNumberOfWordPages(fso, File.path)
  Next
  
  ' カレントDIR配下にあるDIRに対して再帰的に実行する
  Dim Subdir
  For Each Subdir in dir.SubFolders
    ' 再帰呼び出し
    result= result& GetNumberOfWordFilePageAll(fso, Subdir)
  Next
  
  GetNumberOfWordFilePageAll = result
  
End Function

'
'@func GetNumberOfWordPages
'@brief Wordファイルのページ数を取得する
'@param[in] fso       ファイルシステムオブジェクト
'@param[in] filepath  対象ファイル
'
Function GetNumberOfWordPages(fso, filepath)
  
  '拡張子のチェック(wordファイル以外は対象外)
  Dim ExtName
  ExtName = UCase(fso.GetExtensionName(filepath))
  If Not (ExtName = "DOC" OR ExtName = "DOCX") Then
    Exit Function
  End If
  
  ' wordファイルを開く
  Dim wordApp
  Set wordApp = WScript.CreateObject("Word.Application")
  Dim doc
  Set doc = wordApp.Documents.Open(filepath)
  
  ' ファイル名,ページ数を返す
  GetNumberOfWordPages = filepath & "," & doc.BuiltInDocumentProperties(14) & vbNewLine
  
  ' wordファイルを閉じる
  doc.Close
  Set doc = Nothing
  wordApp.Quit
  Set wordApp = Nothing
  
End Function


' @func WriteResultToFile
' @brief 処理結果をファイルに出力
' @param[in] fso      ファイルシステムオブジェクト
' @param[in] filename 出力ファイル名
' @param[in] result   処理結果
'
Function WriteResultToFile(fso, filename, result)
  
  Dim file
  Set file = fso.CreateTextFile("." & "\" & filename)
  Dim header
  header = UCase("ファイル名, ページ数")
  file.WriteLine(header)
  file.WriteLine(result)
  file.close
  Set file = Nothing
  
  MsgBox "処理結果を '" & filename & "' に出力しました。"
  
End Function


実行結果


ちゃんと動作するか適当なワードファイルを用意して試してみます。

カレントにページ数が3のファイルを、サブディレクトリにページ数が1のファイルを作り配置します。

その他、Wordファイル以外を誤ってカウントしないか確認するためにダミーのテキストファイルを配置します。

f:id:segmentation-fault:20171125221856p:plain

f:id:segmentation-fault:20171125221904p:plain


こんな感じで配置しました。


ファイルの配置したらスクリプトをクリックして実行してみます。

f:id:segmentation-fault:20171125221908p:plain

f:id:segmentation-fault:20171125221911p:plain

ちゃんと動いてそうですね。

あとは記載内容のチェックもある程度自動化できればいいなぁ。

図とかは限界がありそうですが。




各社のAPIを使って仮想通貨の価格を表示してみる

以前はcoincheckのAPIだけ使っていましたが、仮想通貨の取引所も増えてきましたので他の取引所が提供しているAPIを試してみました。 pythonで仮想通貨の価格(日本円)表示します。

www.segmentation-fault.xyz

Zaif


APIの公式ドキュメントは下記。

corp.zaif.jp

ソースコード

#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import requests
import json

coins = [
            [1,  'BTC',  'btc_jpy'],
            [2,  'XEM',  'xem_jpy'],
            [3,  'MONA', 'mona_jpy'],
        ]

urlbase = 'https://api.zaif.jp/api/1/last_price/'

def main():
    for i in range(len(coins)):
        response = requests.get(urlbase+coins[i][2])
        if response.status_code != 200:
            raise Exception('return status code is {}'.format(response.status_code))

        rate = json.loads(response.text)

        print("%-4s : \%-10s" % (coins[i][1], rate['last_price']))

if __name__ == "__main__":
    main()


実行結果

[user@localhost zaif]$ date
Sun Nov 12 20:59:35 JST 2017

[user@localhost zaif]$ /usr/local/bin/python3 zaif.py
BTC  : \720000.0
XEM  : \21.1
MONA : \305.7


bitflyer


APIの公式ドキュメントは下記。

lightning.bitflyer.jp

ソースコード

#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import requests
import json

coins = [
            [1,  'BTC',    'btc_jpy'],
            [2,  'FX_BTC', 'fx_btc_jpy'],
        ]

urlbase = 'https://api.bitflyer.jp/v1/getticker?product_code='

def main():
    for i in range(len(coins)):
        response = requests.get(urlbase+coins[i][2])
        if response.status_code != 200:
            raise Exception('return status code is {}'.format(response.status_code))

        rate = json.loads(response.text)

        print("%-6s : \%-10s" % (coins[i][1], rate['ltp']))

if __name__ == "__main__":
    main()


実行結果

[user@localhost bitflyer]$ /usr/local/bin/python3 bitflyer.py
BTC    : \710919.0
FX_BTC : \717699.0


bitbank


APIの公式ドキュメントは下記。

docs.bitbank.cc

ソースコード

#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import requests
import json

coins = [
            [1,  'BTC',     'btc_jpy'],
            [2,  'XRP',     'xrp_jpy'],
            [3,  'MONA',    'mona_jpy'],
            [4,  'BCC(BCH)','bcc_jpy'],
        ]

urlbase = 'https://public.bitbank.cc/'

def main():
    for i in range(len(coins)):
        response = requests.get(urlbase+coins[i][2]+'/ticker')
        if response.status_code != 200:
            raise Exception('return status code is {}'.format(response.status_code))

        result = json.loads(response.text)

        print("%-8s : \%-10s" % (coins[i][1], result['data']['last']))

if __name__ == "__main__":
    main()


実行結果

[user@localhost bitbank]$ date
Sun Nov 12 21:18:20 JST 2017

[user@localhost bitbank]$ /usr/local/bin/python3 bitbank.py
BTC      : \718474
XRP      : \22.762
MONA     : \320.000
BCC(BCH) : \180365


BTCBOX


APIの公式ドキュメントは下記。

https://www.btcbox.co.jp/help/asm

ソースコード

#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import requests
import json

ticker = 'https://www.btcbox.co.jp/api/v1/ticker/'

def main():
    response = requests.get(ticker)
    if response.status_code != 200:
        raise Exception('return status code is {}'.format(response.status_code))

    rate = json.loads(response.text)

    print("BTC_JPY : \%-10s" % (rate['last']))

if __name__ == "__main__":
    main()


実行結果

[user@localhost btcbox]$ date
Sun Nov 12 21:26:59 JST 2017

[user@localhost btcbox]$ /usr/local/bin/python3 btcbox.py
BTC_JPY : \710030


kraken


APIの公式ドキュメントは下記。

www.kraken.com

ソースコード

#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import requests
import json

coins = [
            [1,  'XBT(BTC)', 'xbtjpy', 'XXBTZJPY'],
            [2,  'ETH',      'ethjpy', 'XETHZJPY'],
        ]

urlbase = 'https://api.kraken.com/0/public/Ticker?pair='

def main():
    for i in range(len(coins)):
        response = requests.get(urlbase+coins[i][2])
        if response.status_code != 200:
            raise Exception('return status code is {}'.format(response.status_code))

        rate = json.loads(response.text)

        print("%-8s : \%-10s" % (coins[i][1], rate['result'][coins[i][3]]['c'][0]))

if __name__ == "__main__":
    main()


実行結果

[user@localhost kraken]$ date
Sun Nov 12 21:45:18 JST 2017

[user@localhost kraken]$ /usr/local/bin/python3 kraken.py
XBT(BTC) : \714001.000
ETH      : \34330.00000


まとめ


国内の取引所の差額なんかを一覧にしてみるのも面白そうですね。



Linuxのカーネルモジュールを作って遊んでみる

今回はLinuxのカーネルモジュール(例えばデバイスドライバ)のプログラミングにトライします。

まず今回はHello World的プログラムを作り、次回は/procファイルシステムへのアクセスなど色々試して遊んでみたいと思います。

環境はLinux(CentOS 7)(64bit)です。

カーネルモジュールとは


カーネル・モジュールはLinuxのユーザー空間ではなくカーネル空間で動作するプログラムの事です。

例としてデバイスドライバと呼ばれるものはカーネルモジュールの1つのです。

ユーザー空間のアプリケーションのプログラミングとは少々お作法が事なります。

[参考]
itpro.nikkeibp.co.jp


まずはHello World


どんなプログラミングでも最初はやはりHello Worldを試すのが一般的ですので今回も例にもれずやっていきます。

事前にカーネルモジュールのプログラミングに必要なものをインストールします。

# カーネルモジュール開発に必要なパッケージをインストール
[user@localhost ~]$ sudo yum install kernel-devel
[user@localhost ~]$ sudo yum install kernel-headers


# インストール後の確認
# devel, heeadersがインストールされていればOKです。
[user@localhost ~]$ rpm -aq|grep kernel
kernel-tools-libs-3.10.0-514.26.2.el7.x86_64
kernel-tools-3.10.0-514.26.2.el7.x86_64
kernel-3.10.0-327.el7.x86_64
kernel-3.10.0-514.26.2.el7.x86_64
kernel-headers-3.10.0-693.5.2.el7.x86_64
kernel-devel-3.10.0-514.26.2.el7.x86_64  
kernel-devel-3.10.0-693.5.2.el7.x86_64


準備が整ったらdmesgにHello Worldのログを出力するmymod.cとビルドするためのMakefileを作ります。

mymod.c

#include <linux/module.h>
#include <linux/init.h>

/* お約束的な宣言 */
MODULE_LICENSE("GPL");

/* insmod実行時に呼び出される */
static int mymod_init(void)
{
    printk(KERN_INFO "Hello World\n");
    return 0;
}

/* rmmod実行時に呼び出される */
static void mymod_exit(void)
{
    printk(KERN_INFO "Goodbye World\n");
}

/* 関数の登録 */
module_init(mymod_init);
module_exit(mymod_exit);


Makefile

obj-m := mymod.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean



makeを実行するとビルドが開始されます。ビルド後の出来上がった*.koのファイルがカーネルモジュールです。

[user@localhost driver]$ ls
Makefile  mymod.c


[user@localhost driver]$ make
make -C /lib/modules/3.10.0-514.26.2.el7.x86_64/build M=/home/user/driver modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-514.26.2.el7.x86_64'
  CC [M]  /home/user/driver/mymod.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/user/driver/mymod.mod.o
  LD [M]  /home/user/driver/mymod.ko
make[1]: Leaving directory `/usr/src/kernels/3.10.0-514.26.2.el7.x86_64'


[user@localhost driver]$ ls -lrt
total 204
-rw-rw-r--. 1 user user   156 Nov  2 23:00 Makefile
-rw-rw-r--. 1 user user   787 Nov  2 23:01 mymod.mod.c
-rw-rw-r--. 1 user user     0 Nov  2 23:01 Module.symvers
-rw-rw-r--. 1 user user 52864 Nov  2 23:01 mymod.mod.o
-rw-rw-r--. 1 user user   422 Nov  2 23:03 mymod.c
-rw-rw-r--. 1 user user 44400 Nov  2 23:04 mymod.o
-rw-rw-r--. 1 user user    34 Nov  2 23:04 modules.order
-rw-rw-r--. 1 user user 94184 Nov  2 23:04 mymod.ko ★これがカーネルモジュール


実行結果


カーネルモジュールが出来上がったので実際にロードしてみます。

insmodコマンドでカーネルにモジュールをロード、lsmodでロード中のモジュールを確認できます。

[user@localhost driver]$ sudo insmod mymod.ko


[user@localhost driver]$ lsmod |grep mymod
mymod                  12496  0



[user@localhost driver]$ dmesg |tail
[ 1121.612492] mymod: loading out-of-tree module taints kernel.
[ 1121.612524] mymod: module verification failed: signature and/or required key missing - tainting kernel
[ 1121.612713] Hello World



カーネルモジュールのロードとdmesgにHello Worldが出力されていることが確認できました。

今度はrmmodでモジュールをアンロードしてみます。

[user@localhost driver]$ sudo rmmod mymod


[user@localhost driver]$ lsmod |grep mymod
[user@localhost driver]$


[user@localhost driver]$ dmesg |tail
[ 1121.612492] mymod: loading out-of-tree module taints kernel.
[ 1121.612524] mymod: module verification failed: signature and/or required key missing - tainting kernel
[ 1121.612713] Hello World
[ 1179.087241] Goodbye World



こちらも期待通りdmesgにメッセージが出力されていますね。

次回はもう少し実用的なプログラムを作ってみます。




FREDから日経平均株価を取得してみる(Python)

最近は仮想通貨の取引所が公開しているAPIを使い販売レートを取得したりビットコインを購入したり出来ることを知り色々遊んでいました。

ふと、日経平均株価(N225)とか他の経済情報を収集してデータを分析できたら面白いのでは?と思ったので情報を取得する方法が無いかと思い探してみました。

今回はLinuxでPython3を使って日経平均株価を取得します。

日経平均株価の情報源


ちょっと調べたところFREDという米国のセントルイス連邦準備銀行が運営する経済統計に関するデータベースから取得することができるようです。

YahooやGoogleからも取得出来そうですが、取得禁止だったり非公式だったりと渋り気味でした。


情報源 N225の取得 備考
Yahooファイナンス × APIなし、スクレイピング禁止
Google ファイナンス APIはあるが非公式
FRED


FREDとは

  • セントルイス連銀(ミズーリ州セントルイスにある連邦準備銀行の1つ)が運営する経済データのデータベース
  • 米国経済に関する統計データを公開している。
  • 日経225の平均株価を取得可能。


経済情報を取得するライブラリ


経済情報の収集は各所で公開されているAPIを使うかスクレイピング、クローリングによって行うことが出来ますが自分で実装するのは少々面倒です。

Pythonではそういったデータ収集のためのライブラリであるpandas-datareaderを使うことで簡単に情報が取ってこれます。

インストールはpipで行います。

$ sudo /usr/local/bin/pip3 install pandas-datareader


日経平均株価の取得


ライブラリのインストールが出来たので早速取得してみます。

情報はDataReaderを使って取ってこれます。 開始日と終了日は省略可能です。

DataReader("銘柄", "情報源", "開始日", "終了日")


とりあえず、前日の値をとってみます。

# 日経平均株価を取得する(n225.py)

#!/usr/local/bin/python3

from pandas_datareader import data as web

n225 = web.DataReader("NIKKEI225", "fred", "2017/10/27")

print(n225)


$ /usr/local/bin/python3 n225.py
            NIKKEI225
DATE
2017-10-27   22008.45


こんな結果が得られました。値が合ってるかGoogle先生に聞いてみましょう。

f:id:segmentation-fault:20171028124936p:plain



ちゃんと一致してますね!

あとは色々とデータを集めてきてオレオレ分析してみたいと思います。