読者です 読者をやめる 読者になる 読者になる

Raspberry Pi3 の dhcpcd

Raspberry Pi3(以降、RPi3)のネットワークアドレスをstaticに設定したはずなのに、どういうわけか、そのアドレスに加えてDHCPで取ってきたであろうアドレスもNICに割り当てられているという気持ち悪い現象が前々からあった。

 

具体的にはこんな感じ。

/etc/network/interfaces に以下のような設定をしたにも関わらず、

allow-hotplug eth0
iface eth0 inet static
    address 192.168.20.51
    netmask 255.255.255.0
    gateway 192.168.20.1
    dns-nameservers 192.168.20.1

起動ログには、

My IP address is 192.168.20.51 192.168.20.14 

 と表示されている。

ipコマンドで確認してみても、eth0のセカンダリアドレスとして登録されている。

$ sudo ip addr list
...
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.20.51/24 brd 192.168.12.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 192.168.20.14/24 brd 192.168.12.255 scope global secondary eth0
       valid_lft forever preferred_lft forever

 

 別のPCから 192.168.20.14 にpingを送ってみると疎通するし、ルーターDHCP管理表にもIPアドレスMACアドレスが登録されている。新たな機器を追加したときにアドレスが競合するのも嫌だし、自分の意に反した設定なので何とかしたいと思って調べてみると、dhcpcdなるものが悪さをしているっぽい。

 

sysv-rc-conf や insserv から dhcpcd の自動起動を無効にしても効き目がなかったので、systemctl から dhcpcd.service の自動起動を無効化した。

 

$ sudo insserv -r dhcpcd
$ sudo insserv dhcpcd,stop=2,3,4,5
$ sudo reboot
...
$ sudo service dhcpcd status
 dhcpcd.service - dhcpcd on all interfaces
   Loaded: loaded (/lib/systemd/system/dhcpcd.service; enabled)
  Drop-In: /etc/systemd/system/dhcpcd.service.d
           └─wait.conf
   Active: active (running) since Thu 2017-02-02 19:16:36 JST; 52s ago
  Process: 503 ExecStart=/sbin/dhcpcd -q -w (code=exited, status=0/SUCCESS)
 Main PID: 822 (dhcpcd)
   CGroup: /system.slice/dhcpcd.service
           └─822 /sbin/dhcpcd -q -w

 insservでサービスを停止させてみたけど動いているやん(涙

 

このログをネタに調べてみると、どうやらdhcpcdデーモンの自動起動はrcスクリプトではなく、systemdによって管理されているっぽい。

 

$ sudo systemctl disable dhcpcd.service
$ sudo reboot
...
$ sudo service dhcpcd status
● dhcpcd.service - dhcpcd on all interfaces
   Loaded: loaded (/lib/systemd/system/dhcpcd.service; enabled)
  Drop-In: /etc/systemd/system/dhcpcd.service.d
           └─wait.conf
   Active: inactive (dead)

systemctlでサービスを停止させてみたら止まったじょ!

 

これにより起動ログも、staticで指定したアドレスのみになりスッキリした。

My IP address is 192.168.20.51 

 

 

 参考Webページ

配列のリファレンスをサブルーチンに渡す

Perlで配列をルーチン間でやりとりする時のメモです。

サブルーチンに引数として配列を渡すとき、配列をそのまま渡せばスカラーに展開されて値渡しされますが、リファレンス演算子をつけてリファレンスとして渡せば参照渡しとなります。(多分)

 

呼び出し先でリファレンスの実体にアクセスするにはどうすればいいのかというと、アロー演算子を使えばよいのですが、配列の大きさを求めるときに少しハマったので書き方を残しておきます。(...フレーズでくくるだけです)

$#{$array_ref}

foreach使えばいいじゃんと言ってしまえばそれまでですがw

 

my @array = ("sanzo", "goku", "gojo", "hakkai");
&printArray(\@array);
sub printArray { my ($array_ref) = @_; for (my $i = 0; $#{$array_ref} >= $i; ++$i) { print "$i: $array_ref->[$i]\n"; }
}

 

Chart.jsのグラフがiPhoneではチラつく

Chart.jsを使ってグラフ(棒グラフでも円グラフでも)をWebブラウザに表示させたときのこと。WindowsMac OS上のブラウザではhoverしてもclickしてもcanvas領域の表示は問題ないのだけど、iOS上のSafariChromeで同様のことをしてみると、一瞬canvas領域がグレー(タップ動作によるハイライト?)になってチラついてしまう現象が起きた。

Android上のブラウザでは問題ないので、iOS固有の問題なのかなと思って調べてみると、styleの -webkit-tap-highlight-colorプロパティをtransparentにすることで解決できた。

<canvas id="sampleChart" width="400" height="400" style="-webkit-tap-highlight-color: transparent">

 

このスタイル指定にはベンダープリフィックスwebkitが付いているので、SafariChromeにしか効かないのかな?と思ったけど、iOSFirefoxからアクセスしてみるとチラつかずに表示できたので、ひとまずこの書き方でいってみよう。

 

 

参考Webページ

XMLHttpRequestによる同期通信

同期通信によって同一オリジンの別ファイルを読み出そうとしたときにハマってしまったのでメモとして残しておきます。

やりたいこととしては、複数の別のファイルを読み込んで、<div> ~ </div> にその内容を表示させるというものです。for文を回してファイルを複数回取得し、もしファイルが存在しなかったら、代わりに「ファイルが存在しません」というメッセージを <div> ~ </div> に表示させます。

 

読み込むファイルは、page1.html ~ page4.html とし、表示先の <div> の id をそれぞれ "info1" ~ "info4" とします。

プログラムのキモとしては次のようなことになると思います。

  • XMLHttpRequest.open(...) の第3引数をfalseにする
  • XMLHttpRequest.send(...) のあとにresponseTextを取得する
    (イベント処理をしない)
  • XMLHttpRequestに関係する処理を try { ... } でくくる

こうすることでファイルの取得に失敗した場合は、catch節に入ってくるようになります。

 

<script type="text/javascript">
  window.onload = function () {

    var files = [
      "./page1.html",
      "./page2.html",
      "./page3.html",
      "./page4.html"
    ];
    
    var loop = files.length + 1;
    for (var i = 1; loop > i; ++i) {

      try {
        var xhr = new XMLHttpRequest();

        // 同期処理で外部ファイルを処理する
        xhr.open("GET", files[i], false);

        // リクエストを送る
        xhr.send(null);

        // 同期処理なのでresponseをこのタイミングで受け取れる
        document.getElementById("info" + i).innerHTML = xhr.responseText;		
      }
      // Ajax通信でエラーが起きた場合
      catch(e) {
        document.getElementById("info" + i).innerHTML = "<p>ファイルが存在しません</p>";
      }
    }
  };
</script>

<h2>page1の内容</h2>
<div id="info1"></div>
<hr>

<h2>page2の内容</h2>
<div id="info2"></div>
<hr>

<h2>page3の内容</h2>
<div id="info3"></div>
<hr>

<h2>page4の内容</h2>
<div id="info4"></div>

 

 

参考Webページ

HTML5/CSS3で二重下線を引くには

ウェブデザインの話です。

 

HTML5より前の時代では、ウェブページに下線を引きたい場合は <u> ~ </u> でいけましたが。HTML5では <u>タグの意味合いが変わり、下線は <span style="text-decoration: underline"> ~ </span> のようにして引きます。

  • HTML5より前: <u> ~ </u>
  • HTML5:<span style="text-decoration: underline"> ~ </span>

それでは、二重下線の場合はどうでしょう?

一部のブラウザでは、text-decoration: underline double のようにstyleを指定してやるといいみたいですが、IEChromeでは表示されません。

そこで紹介したいのが、border-bottomを使った実現方法。ググってみると、ちまたのWebページでもよく紹介されているやり方ですが、実際にやってみるとこんな風に下のほうに隙間が出来てしまうのが難点です。

 

上にある赤の二重線のようにするには、border-bottomのほかにdisplayとline-heightを指定してあげる必要があります。

  • border-bottom: 3px double;
  • display: inline-block;
  • line-height: 85%;

line-heightの値を調整する(値を大きくすると離れる)ことで、ぴったりした二重下線を引けるようになります。

 

より確実な方法としては、二重線の画像を用意してbackground-imageとして指定する方法があるみたいですが、border-bottomを使ったほうがお手軽な感じです。

 

 

参考Webページ

 

Wide character in die at

Perlエンコードに関する話です。

結論から言ってしまうと、この警告メッセージは「Wide character in print at」のSTDERR(標準エラー)版なので、binmode(STDERR, ":utf8");を書いておくことで解決できるようになります。

f:id:tuttitan:20170123133157p:plain

 

「Wide character in print at」の問題は、出力しようとしている文字にutf8フラグなるものがくっついていると起こるみたいで、binmode(STDOUT, ":utf8");を書くことで問題を回避できます。これは『標準出力の文字エンコードはutf8ですよ』ということを指定するための文言っぽいです。

 

die "エラーが発生したので終了します: $!";
のようなコードをutf8でエンコードされているplファイルに書いて、その行が実行されると「Wide character in die at」が現れることがあります。

print は文字列をSTDOUTに出力し、dieは文字列をSTDERRに出力するためbinmode(STDOUT, ":utf8");と書いておいただけでは警告メッセージが出てしまいます。なので、ソースコードをutf8で書いた場合は、STDOUTと同様にSTDERRのbinmodeも指定しておきましょう。

# エンコードの設定
use utf8;
binmode(STDOUT, ":utf8");
binmode(STDERR, ":utf8");

 

 

参考Webページ

テキストファイルの中からCJK互換漢字をあぶり出す

先日、メモ帳のテキストにおかしな漢字(CJK互換漢字)があるという感じの記事を書きましたが、そんな漢字をあぶり出すスクリプトを考えましたので今回はその紹介。

tuttitan.hatenablog.com

 

スクリプトPerlで作られており、内容としてはテキストファイルを開いて1文ずつ文字コードを調査していき、コード的にU+F900~U+FF00の文字があったら表示するというものです。

CygwinPerl環境で動作確認していますが、環境が変わると文字が化けたり正しいコードが取れない可能性があるので参考にする場合はご注意下さい。

文字コード関連でのはまりどころとしては、STDOUTをutf8に設定するところと、テキストファイルをopenするところでutf8を指定するところでしょうか。なお、テキストファイルはutf8(BOMなし)改行(LF)でエンコードされている前提です。

 

ちょいと汚いですが、以下がコードになります。

#!/usr/bin/perl

use strict;
use warnings;

# エンコードの設定
use utf8;
binmode(STDOUT, ":utf8");
binmode(STDERR, ":utf8");

# 文字色の設定
use Term::ANSIColor qw(:constants);
$Term::ANSIColor::AUTORESET = 1;

print "Script Start...\n";

if (0 != $#ARGV) {
    die "開くファイルを引数で指定して下さい";
}

unless (-e $ARGV[0]) {
    die "$ARGV[0]は存在しません";
}

my $file = $ARGV[0];  # ファイル名
our $cntFind = 0;


open(FDI, "<:utf8", "$file");

my $content;  # ファイルの全内容

# 一時的に入力セパレータを無効して$contentにすべて読み込む
{
    local $/ = undef;
    $content = <FDI>;
}

my $cntLine = 1;
my $column  = 1;

my @chars = split(//, $content);
my $compatiCode1 = 63744;  # 0xF900
my $compatiCode2 = 65280;  # 0xFF00

for (my $x = 0; $#chars >= $x; ++$x) {

    my $code = ord($chars[$x]);

    # CJK互換文字を見つけたら表示する
    if (($code >= $compatiCode1) &&($code < $compatiCode2)) {
        print BOLD RED "NG";
        printf("  line: %4d | col: %3d | char: %s(0x%x)\n", $cntLine, $column, $chars[$x], $code);
        ++$cntFind;
    }

    ++$column;  # 1文字処理したのでカラムを+1する

    # 行末の処理
    if ($chars[$x] =~ /\n/) {
        $column  = 1;
        ++$cntLine;
    }
}
close(FDI);

print "\n";
print "=============================\n";
print "見つかった数: $cntFind\n";
print "=============================\n";
print "\n";

print "...Script End\n";