君は心理学者なのか?

大学時代に心理学を専攻しなぜかプログラマになった、サイコ(心理学)プログラマかろてんの雑記。

ババァ!ノックしろよッ!ってならないためのlinuxパーミッション入門

f:id:karoten512:20171223225621j:plain

思春期あるある

思春期を超えたことがあるみなさんなら

共感していただけると思うのですが、

突然親が部屋に来訪してくるとビビりますよね。

やましいことがあってもなくてもビビりますよね。

今回は、

linuxなら、
親が勝手に部屋に入ってこれなくなるので、
安全だよ

という話をしようと思います。

環境を用意する

今回はCentOS7を環境として用意しました。

軽く試したい時、dockerさんにはとてもお世話になっております。。。

$ docker run -it centos:centos7

母ユーザと俺ユーザを作成し、それぞれの部屋を作成

$ useradd haha
$ useradd ore

なお、ここで

$ cat /etc/passwd

とすると、以下のようにユーザが追加されていることがわかります。

ore:x:1000:1000::/home/ore:/bin/bash
haha:x:1001:1001::/home/haha:/bin/bash

また、

$ ls /home
haha  ore

となっており、homeディレクトリにhahaとoreディレクトリが追加されています。

userを追加すると、それぞれのユーザが使える部屋も同時に追加される感じですね。

俺の部屋で怪しい本を生成

$ su ore
$ cd /home/ore
$ touch ayashii_book

俺の部屋に怪しい本をおきます。

母親が俺の部屋に入ろうとすると、、、

$ su haha

ユーザを母親に切り替えます。

$ cd /home/ore
bash: cd: ore: Permission denied

母親は、俺の部屋に入れない!

なぜ部屋に入れないのか

ここでoreディレクトリの

パーミッションを確認してみましょう。

$ ls -la
drwx------. 2 ore  ore  4096 Dec 22 15:48 ore

このパーミッションを図にすると、

以下のようになります。

f:id:karoten512:20171223230537p:plain

つまり、

  • oreディレクトリは、oreユーザに対して、読み、書き、実行を許している

  • 他のユーザに対しては何も許していない

ということになります。

だから、hahaユーザは入ることもできないのです。

やったね!

ディレクトリの場合、

 実行権=そのディレクトリに入れる権利

 であることは覚えておきましょう)

dqn.sakusakutto.jp

どうしたら母が入れるようになるのか

ディレクトリに入れるようにするためには、

このディレクトリに対して、

othersが実行権を持てばよいです。

f:id:karoten512:20171223231650p:plain

実際にやってみましょう。

$ su ore
$ chmod 701 ore
$ drwx-----x. 2 ore  ore  4096 Dec 22 15:48 ore

この701とは何か、ということですが、

これはrwxのパーミッションを数字で表したものになります。

末尾の1が、実行権を表してます。

(こちらについてはまた解説いたします)

$ su haha
$ cd ore

入れました!

しかし、部屋の中に何があるかはみれない

俺の部屋でlsをしてみます。

$ ls
ls: cannot open directory .: Permission denied

なるほど。部屋には入れるけど

中はみれないのか。

今度はothersに読み取り権限を与える

今度は、以下の図のようにします。

f:id:karoten512:20171223231829p:plain

今度はothersに読み取り権限を与えてみましょう。

$ su ore
$ cd /home
$ chmod 705 ore

母親、再来

$ su haha
$ cd /home/ore

f:id:karoten512:20171223232109p:plain

$ ls
ayashii_book

見つかったッ!

※ くだらなくて申し訳ありません

まとめ

このように、

思春期の子供はlinuxでuseraddすれば、

母親が入れないホームディレクトリが生成されるので

健やかな日々を送れると思います。

みなさんも、

パーミッションをうまく利用して快適ライフを送りましょう。

もうPermission deniedなんて怖くない!〜linuxのパーミッションについてかなり丁寧に説明してみる〜

開発中よく目にするエラー

Permission denied.

環境構築中、よくこのエラー見ますよね。

よく見る割に「とりあえずsudoで無理やり対応」という雑な対応が多い気がしたので、

まずはパーミッションについて整理してみようと思いました。

前提

そもそも、linuxはみんなで使うものだった

今でこそ一人一台コンピュータを持つのは当たり前になりましたが、

昔コンピュータはすごく高価だったので、一台のコンピュータを皆で使っていました。

f:id:karoten512:20171223013706p:plain

これだとプライバシーがなくなる

しかしこれだと、こういう問題がおきます。

Aさんが、自分のちょっと言えない秘密を書いたファイルを作成、

保存しました。

f:id:karoten512:20171223013823p:plain

コンピュータはみんなで使うもの。

Aさんのファイルはみんなに共有され、

そしてみんなに書き換えられてしまいました。これは非常にこまる。

理想

  • 作った人は読めるし編集できる

  • 他の人は読めないし編集もできない

となっているのが理想ですね。

f:id:karoten512:20171223014154p:plain

図にするとこんな感じ。

実際のlinux

これを実現するために、linuxでは

全てのファイル・ディレクトリに「所有者」という属性を持たせています。

そして、

所有者がファイルを触る時と、

所有者以外の他人がファイルを触る時、

それぞれの時に可能な操作(読み、書き、実行)が

設定できるようになってます。

f:id:karoten512:20171223014348p:plain

上の例だと、

所有者はそのファイルに対して読み、書き、実行ができますが、

所有者以外の人は何も出来ない、という設定ですね。

もう少し実際の表示に近づけるとこんな感じです。

f:id:karoten512:20171223015102p:plain

rはread, wはwrite, xはexecuteの略です。わかりやすいですね。

実際はowner以外にも、groupという概念があります。

これを使うと、

  • 開発者グループの人はこのファイルを読めるようにしたい

といった設定が可能です。

f:id:karoten512:20171223020439p:plain

この「ファイル・ディレクトリに対してできること」のことを、

パーミッションと言います。

コマンドラインで確認してみる

それでは、このfileAについて、

所有者、グループ、パーミッションを確認してみましょう。

$ ls -al
-rwxr-----. 1 A    dev     0 Dec 22 16:56 fileA

なにかでてきましたね。

先ほどの図と比べてみましょう。

f:id:karoten512:20171223020740p:plain

色分けしたとおりです。

なお、このパーミッションを変えたいときは、

chmod

ファイルの所有者・所有グループを変更したいときは、

chown
chgrp

などのコマンドを使います。

結局Permission deniedとは何なのか

「ファイルに設定されているパーミッション以外の操作をしようとした時」

に出るエラーです。

先ほどの例なら、所有者でも所有グループでもない人が、

そのファイルを読もうとしたり書こうとした時に発生します。

これを知っておけば、

エラーが起きた時に

「ああ、今のユーザでは出来ない操作なんだな」

「ユーザを変えよう」

パーミッションを変えよう」

「ファイルの所有者・グループを変えよう」

などの把握・対処ができると思います。

rpmコマンドの使い方を整理してみる(LPIC対策)〜yumとの違いも比較してみた〜

rpmとは

パッケージ管理システム。

パッケージとは、すごくざっくりいうとwindowsでいう「ソフトウェア」にあたる。

rpmはそれを管理するシステムなので、

linuxに何かパッケージをinstallしたり、

uninstallしたりするときに使用する。

rpmを使用してみる

-q [パッケージ名] installされていればバージョンを表示

$ rpm -q nginx
nginx-1.12.2-1.el6.ngx.x86_64

パッケージに関する情報を調査し表示するには、

-qオプションを使用する。

それと他のオプションを組み合わせて使用する。

-i 詳細情報を表示

$ rpm -iq nginx
Name        : nginx                        Relocations: (not relocatable)
Version     : 1.12.2                            Vendor: Nginx, Inc.
Release     : 1.el6.ngx                     Build Date: 2017年10月17日 22時25分44秒
Install Date: 2017年11月09日 00時13分32秒      Build Host: centos6-amd64-builder-builder.gnt.nginx.com
Group       : System Environment/Daemons    Source RPM: nginx-1.12.2-1.el6.ngx.src.rpm
Size        : 2594410                          License: 2-clause BSD-like license
Signature   : RSA/SHA1, 2017年10月17日 22時47分16秒, Key ID abf5bd827bd9bf62
URL         : http://nginx.org/
Summary     : High performance web server
Description :
nginx [engine x] is an HTTP and reverse proxy server, as well as
a mail proxy server.

-l パッケージに含まれるすべてのファイルを表示

$ rpm -ql nginx
/etc/logrotate.d/nginx
/etc/nginx
/etc/nginx/conf.d
/etc/nginx/conf.d/default.conf
/etc/nginx/fastcgi_params
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/mime.types
/etc/nginx/modules
...省略

-c パッケージに含まれる設定ファイルを表示

$ rpm -qc nginx
/etc/logrotate.d/nginx
/etc/nginx/conf.d/default.conf
/etc/nginx/fastcgi_params
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/mime.types
/etc/nginx/nginx.conf
/etc/nginx/scgi_params
/etc/nginx/uwsgi_params
/etc/nginx/win-utf
/etc/sysconfig/nginx
/etc/sysconfig/nginx-debug

[参考] yumについて

1つのパッケージはそのパッケージだけでは動かないことがある

1つのパッケージはいくつかのパッケージを組み合わせて動いていることが多い。

(パッケージが別のパッケージに「依存している」という)

なので、rpmで1つのパッケージをインストールするだけでは動かないこともある。

どうやったら動くのか

1つのパッケージをインストールする時、

使用している他のパッケージも一緒にインストールする必要がある。

ただし、rpmで1つ1つライブラリをinstallしていくのはとても面倒である。

そこでyum

yumrpmと違って、

1つのパッケージをinstallするとき、

使用している他のパッケージも勝手にインストールしてくれる。

(「依存性の解決」という)

基本yumを使う

基本的には、

rpmだと面倒な「依存性の解決」をしてくれるyumを使おう。

lddコマンドでプログラムが参照している共有ライブラリ一覧を取得する(LPIC対策)〜依存関係とは何か〜

共有ライブラリとは

共有ライブラリとは、

「いろんなプログラムから使えるプログラムの部品」

実際に共有ライブラリをみてみる

たとえばvimが使用している共有ライブラリ。

$ ldd /usr/local/bin/vim
    linux-vdso.so.1 =>  (0x00007ffcae5e8000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f5dfe3ef000)
    libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007f5dfe1ce000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f5dfdfca000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f5dfdc36000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f5dfe673000)

たとえばgit。

$ ldd /usr/local/bin/git
    linux-vdso.so.1 =>  (0x00007fff94977000)
    libz.so.1 => /lib64/libz.so.1 (0x00007fd9d8d51000)
    libcrypto.so.10 => /usr/lib64/libcrypto.so.10 (0x00007fd9d896c000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fd9d874f000)
    librt.so.1 => /lib64/librt.so.1 (0x00007fd9d8547000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fd9d81b3000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007fd9d7faf000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fd9d8f67000)

vimとgitでは、

libc.so.6というライブラリを共通で使っていることがわかる。

なお、使っているライブラリとプログラムの間には、

「依存関係」

がある。

yumはこの依存関係を解決してパッケージをinstallしているのかな。

依存関係というものがぼんやりとわかった気がする。

エクスペクト・パトローナム!守護霊よ来たれ! くらいわかりやすい呪文「git push origin master」

Gitコマンド、呪文みたいだよね

みなさんこんにちは。

git push origin master

Git、いきなり使い始めると、

Gitコマンドがただの呪文のように見えますよね。

Gitコマンド使い始めの頃は、

ハリーポッターででてくる浮遊呪文

「ウィンガディアム・レヴィオーサ!」

みたいに、

単語自体には意味がない、丸覚えするしかないものだと思ってました。

※ きっとこれも調べたら意味はあるとは思います

実は「エクスペクト・パトローナム」くらいわかりやすい

ハリーポッターに、

エクスペクト・パトローナム(Expecto patronum)(守護霊よ来たれ)

f:id:karoten512:20171214221154j:plain

って呪文がありますよね。

これをとなえると、

たしかきれいな馬みたいな守護霊がやってきて、

ディメンターをふっとばしてくれる、そんなすごい呪文です。

実はこの呪文、メッチャわかりやすい呪文なんですよ。

なので、そのまんまなんですよね。

なにがいいたいかっていうと

git push origin master

この呪文も、じつはめっちゃわかりやすくて、

そのまま解釈できるってことなんです。

git push origin master

git

Gitコマンドですよ

push

サーバにソースコードを送りますよ

origin

originというサーバ(リポジトリ)に送りますよ

master

masterブランチに送りますよ

以上です。簡単でしょ?

originというサーバって何?

git remote show origin

と打ってみましょう。

* remote origin
  Fetch URL: git@github.com:carotene4035/achive.git
  Push  URL: git@github.com:carotene4035/achive.git

こんなのがでてきますよね。

この「origin」というのは、実はリポジトリURLのあだなのようなもので、

git push origin master

というのは、

上の例で言えば、

git push git@github.com:carotene4035/achive.git master

と同じなのです。

Gitコマンドわかりやすい

こうして紐解いてみると、Gitコマンドって結構わかりやすい。

ハリーポッターの呪文と一緒に覚えちゃいましょう。

Enjoy GIt !

早とちりプログラマの失敗から学ぶデザインパターン(Factory Method:適用後)

f:id:karoten512:20171213011506p:plain

このシリーズについて

このシリーズは

  • 後先のことをなにも考えずに実装してしまう『早とちりプログラマ

  • すぐに仕様変更を加える『後出し上司』

のという魅力的な2人から、

デザインパターンの有用さを学んでいこうという素敵な企画です。

(早とちりプログラマのモデルは私です。。。)

要件

上司「コンサートでピアノが聴けるようにしてよ」

わたし「わっかりました〜!!!」

わたし「ピアノ以外もきっと対応してくれっていわれそうだな」

わたし「さて、どうするか。。。」

いろんな楽器に対応できるようポリモーフィズムを用いる

ポリモーフィズムは継承によるものとインターフェースによるものがありますが、

今回はインターフェースで実装します。

演奏できるというインターフェース

interface Playable {
  play(): void;
}

ピアノクラス

class Piano implements Playable
{
    public play(): void
    {
        console.log('ポロンポロン');
    }
}

コンサートクラス

class Concert
{
    private instrument: Playable;
    
    constructor()
    {
        this.instrument = new Piano();
    }
    
    public start(): void
    {
        this.instrument.play();
    }
}

Factory Methodを適用

わたし「このままだとConcertがPianoに依存しているから、

それをなんとかしたいな。。。Factory Method使ってみるか」

楽器生成クラス

class InstrumentFactory
{
    static create(instrumentCode: string): Playable {
        if (instrumentCode === 'piano') {
            return new Piano();
        }
    }
}

コンサートクラス修正

class Concert
{
    private instrument: Playable;
    
    constructor()
    {
        this.instrument = InstrumentFactory.create('piano');
    }
    
    public start(): void
    {
        this.instrument.play();
    }
}

わたし「よし、これでConcertクラスから特定のクラスのnewが消えたな」

仕様変更

上司「クライアントがさ、やっぱりピアノじゃなくてギターじゃないとダメだって」

修正

ギタークラス

class Guitar implements Playable
{
    public play()
    {
        console.log('ジャーン');        
    }
}

楽器生成クラス追加

class InstrumentFactory
{
    static create(instrumentCode: string): Playable {
        if (instrumentCode === 'piano') {
            return new Piano();
        } else if (instrumentCode === 'guiltar') {
            return new Guitar();
        }
    }
}

コンサートクラス修正

class Concert
{
    private instrument: Playable;
    
    constructor()
    {
        this.instrument = InstrumentFactory.create('guitar'); // 修正
    }
    
    public start(): void
    {
        this.instrument.play();
    }
}

結果

呼び出す側の修正は、 楽器名を変えるだけでよくなりました。

デザインパターンを使用すると、記述量は増えますが、

既存のソースコードの書き直しが劇的に減ります(3箇所→1箇所)

早とちりプログラマの失敗から学ぶデザインパターン(Factory Method:適用前)

f:id:karoten512:20171213011506p:plain

このシリーズについて

このシリーズは

  • 後先のことをなにも考えずに実装してしまう『早とちりプログラマ

  • すぐに仕様変更を加える『後出し上司』

のという魅力的な2人から、

デザインパターンの有用さを学んでいこうという素敵な企画です。

(早とちりプログラマのモデルは私です。。。)

要件

上司「コンサートでピアノが聴けるようにしてよ」

わたし「わっかりました〜!!!」

※ typescriptでの実装となります。

ピアノクラス

class Piano
{
    public play()
    {
        console.log('ポロンポロン');
    }
}

コンサートクラス

class Concert
{
    private piano: Piano;
    
    constructor()
    {
        this.piano = new Piano();
    }
    
    public start()
    {
        this.piano.play();
    }
}

使い方

const concert = new Concert();
concert.start();

仕様変更

わたし「余裕じゃん。一発で終わったわ」

上司「クライアントがさ、やっぱりピアノじゃなくてギターじゃないとダメだって」

わたし「お安い御用です!」

変更方法

追加:ギタークラス

class Guitar
{
    public play()
    {
        console.log('ジャーン');        
    }
}

変更:コンサートクラス

class Concert
{
    private guitar: Guitar; // 書き換え
    
    constructor()
    {
        this.guitar = new Guitar(); // 書き換え
    }
    
    public start()
    {
        this.guitar.play(); // 書き換え
    }
}

わたし「3箇所変更かぁ〜。めんどいなぁ」

仕様変更

上司「ホントはさ、個人的にマンドリンがいいと思うんだよね。

   変えちゃってよ」

わたし「(個人的にって。。クライアント大丈夫か?)わ、わかりました〜」

変更方法

  • マンドリンクラスの作成

  • コンサートクラスの3箇所を書き換え

わたし「なんか同じところばかり修正してる気がする、、、」

わたし「楽器が変わるたびにコンサートクラスの書き換えなきゃいけないのか。。。

    なんか嫌な予感がするな。。。」

仕様変更

上司「やっぱピアノに戻してくれない?! 急いで!」

わたし「えぇ!」

上司「このコンサート会場マンドリン使えないらしいんだよ!

    クライアントはカンカンだ!

    すぐできるでしょ? 10秒で実装しな!」

わたし「そんなむちゃな!」

上司「急がないと納期に間に合わねーんだよ!!」

わたし「お前のせいじゃねーか!(わかりました!)」

上司「お、お前。。。上司になんて口を!」

〜終〜

f:id:karoten512:20171213012243p:plain

どうしてこうなった

クラスの中で特定のクラスをnewしてしまっているから

あるクラスの中で、いろんなクラスを使用するような拡張が予想される場合、

特定のクラスをnewしてしまっている(今回でいうPiano)と、

やっぱり別の特定クラスを使いたい(今回でいうGuiter, Mandolin)、、、

となった時にかなりの書き換えが発生することが多いです。

解決方法

このような変更に対して、

修正を最小限におさえるためにはどうしたらよいでしょうか。

最小限の修正に抑えれば、バグも少なくなるし仕事もサボれるはず。

続きは次回。。。