20210306のLinuxに関する記事は7件です。

自宅を24 -TWENTY FOUR-のCTU化 CISCO 7960GをSIP化しAsteriskに収容

自宅を24 -TWENTY FOUR-のCTU化 CISCO 7960GをSIP化しAsteriskに収容

はじめに

いまさらですが、最近24にはまってます。
24のCTU(Counter Terrorist Unit)で頻繁に登場するCISCOのIP電話を自宅で使いたいということでAsteriskに収容しました。
下記サイトを参考にRaspberry Pi 4 model BのAsterisk(GIT-master-134d2e729d)を使いSIP電話として環境設定しました。
https://ameblo.jp/sentakuc/entry-12468287493.html

CISCO 7960Gを購入

オークションにてCISCO 7960GをACアダプタ付きを4000円で購入。
よく確認せず日本版を買ってしまったので、画面表示やハードキーに日本語表記が・・
SIP化後画面表示は英語表記となり問題なく動作します。

SIP版ファームウェアのダウンロード

デフォルトではSCCP(Skinny Call Control Protocol)版であり、Asteriskに収容できない。
そこで下記サイト
http://www.3cx.com/sip-phones/cisco-7940g-7960g/
でリンクされている
http://downloads.3cx.com/downloads/misc/legacy-phones/cisco-79xx.zip
よりSIP版ファームウェアをダウンロード

TFTPサーバのセットアップ

ファームウェアや背景画像、着信音をCISCO 7960Gにアップロードするため、tftpサーバをインストール

sudo apt-get update
sudo apt-get install tftp-server
sudo systemctl enable tftpd-hpa.service
sudo systemctl start tftpd-hpa.service

TFTPサーバのrootディレクトリ( /srv/tftp)にダウンロードしたcisco-79xx.zipの中身をコピー

Asteriskに端末の設定を追加

/etc/asterisk/sip.confに7960Gの設定を追加

sip.conf

[105]
type=friend
username=105
nat=no ;asteriskがnat内にいる環境だが、本設定でしか動かなかった
secret=password ;端末のパスワードなので変更ください
host=dynamic
canreinvite=no
caninvite=no
context=inside ;extensions.confのcontext似合わせて設定
qualify=yes
callerid="hoge hoge" ;表示名(オプション)

7960Gの設定ファイルの作成

/srv/tftpに下記設定ファイルを作成

XMLDefault.cnf.xml

<Default>
  <callManagerGroup>
     <members>
        <member priority="0">
           <callManager>
              <ports>
                 <ethernetPhonePort>2000</ethernetPhonePort>
                 <mgcpPorts>
                    <listen>2427</listen>
                    <keepAlive>2428</keepAlive>
                 </mgcpPorts>
              </ports>
              <processNodeName></processNodeName>
           </callManager>
        </member>
     </members>
  </callManagerGroup>
  <loadInformation7  model="Cisco 7960">P0S3-8-12-00</loadInformation7>
<authenticationURL></authenticationURL>
 <directoryURL></directoryURL>
 <idleURL></idleURL>
 <informationURL></informationURL>
 <messagesURL></messagesURL>
 <servicesURL></servicesURL>
</Default>                                                      

上の

<loadInformation7  model="Cisco 7960">P0S3-8-12-00</loadInformation7>

にダウンロードしたファームウェアのファイル名から拡張子を除いたものに書き換え

SIPDefault.cnf

image_version: P0S3-8-12-00
proxy1_address: "192.168.1.2"            ; Can be dotted IP or FQDN
proxy1_port: "5080"
proxy2_address: ""              ; Can be dotted IP or FQDN
proxy3_address: ""              ; Can be dotted IP or FQDN
proxy4_address: ""              ; Can be dotted IP or FQDN
proxy5_address: ""              ; Can be dotted IP or FQDN
proxy6_address: ""              ; Can be dotted IP or FQDN
proxy_register: 1
messages_uri:   "1"
phone_password: "cisco" ; Limited to 31 characters (Default - cisco)
sntp_mode: unicast
sntp_server: "192.168.1.1"
time_zone: "JST" ; assuming you're in GMT
time_format_24hr: 1 ; to show the time in 24hour format
date_format: "Y/M/D"  ; format you would like the date in
dial_template: dialplan

上記も同様にファームウェアのバージョンを記入し、proxy1_address,proxy1_portでSIPサーバ(Asterisk)のIPアドレス,port番号を指定。
オプションでsntpサーバがある場合は設定

SEP"7960GのMACアドレス".cnf.xml

<device>
<loadInformation model="IP Phone 7960">P0S3-8-12-00</loadInformation>
</device>

7960GのMACアドレスが001122334455だった場合、ファイル名は
SEP001122334455.cnf.xml

上記も同様にファームウェアのバージョンを記入。
MACアドレスは本体裏面下部にシールで張ってありました。

SIP"7960GのMACアドレス".cnf.xml

image_version: P0S3-8-12-00
line1_name: "105"
line1_authname: 105
line1_shortname: "Line 1" ; displayed on the phones softkey
line1_password: "password"
line1_displayname: "hoge hoge"; the caller id
proxy1_port: "5080"
proxy1_address: "192.168.1.2"
# Line 2 Setup
#line2_name: 1261
#line2_authname: "1261"
#line2_shortname: "Line 2"
#line2_password: "secret"
#line2_displayname: "John Baxendale";
# Phone Label (Text desired to be displayed in upper right corner)
#phone_label: "Siftah.net  " ; add a space at the end, looks neater
phone_password: "cisco" ; Limited to 31 characters (Default - cisco)
user_info: none
telnet_level: 2
logo_url: "http://192.168.1.2:8080/CTU_Logo.bmp"

sip.confで設定したusername,secret,calleridを設定
SIPサーバ(Asterisk)のIPアドレス,port番号も設定
背景画像もオプションで設定できるが、URL指定が必要だったので、ローカルのWebサーバに下記からダウンロードしたCTU_PACK中の画像を置いた
ctu_packには、あのCTUの着信音も入っている。
https://www.ip-phone-forum.de/threads/ctu-style-pack-f%C3%BCrs-7940-7960.78863/
https://www.ip-phone-forum.de/attachments/ctu_pack-zip.4526/

RINGLIST.DAT

着信音を変更する
上記ctu_pack中にある
* RINGLIST.DAT
* Ring1.pcm
* Ring2.pcm
* Ring3.pcm

を/srv/tftpにコピー
本体の設定メニューボタンからRing Typeの設定で選択できる。
ちなみにRINGLIST.DATは

CTU Ring 1      Ring1.pcm
CTU Ring 2      Ring2.pcm
CTU Ring 3      Ring3.pcm

のように、

7960Gでの表示名 ファイル名

というフォーマットとなっている

DHCPオプションでのTFTPサーバアドレスの通知

7960GにTFTPサーバのアドレスを通知します。
7960GはDHCPでIPアドレスを取得するが、DHCPオプションの66 TFTP Server NameでTFTPサーバのIPアドレスを通知できる。
dhcpdで設定する場合は下記等参照
https://kazmax.zpp.jp/cmd/d/dhcp-options.5.html

私はYAMAHAのnvr510で設定したため、下記設定をconfigに追加

dhcp scope option 1 tftp_server_name=192.168.1.2

再起動で設定完了

7960Gを再起動すれば、ファームウェアが更新され下記状態に!
image.jpg

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Linuxのページキャッシュのwrite back処理概要

はじめに

ページキャッシュのwrite backを行うまでの流れに関して記憶があいまいであったため、ソースコードを確認した。せっかくなので、メモをする。
参照したLinuxカーネルのバージョンは5.10.20である。

ページキャッシュにwriteするまでの流れ

write()システムコールからたどる

Buffered I/Oがどのようになっているのか、writeから読んでいく。

fs/read_write.c
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, 
        size_t, count)
{
    return ksys_write(fd, buf, count);
}
fs/read_write.c
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
// 略
     if (file->f_op->write)
         ret = file->f_op->write(file, buf, count, pos);
     else if (file->f_op->write_iter)
         ret = new_sync_write(file, buf, count, pos);
     else
         ret = -EINVAL;

この文書では、ファイルシステムはEXT4を題材にしてコードを読むこととしたい。file_operations構造体は以下のようになっており、writeハンドラはセットされない。

fs/ext4/file.c
const struct file_operations ext4_file_operations = {
    .llseek     = ext4_llseek,
    .read_iter  = ext4_file_read_iter,
    .write_iter = ext4_file_write_iter,

よって、今回の場合、new_sync_write()が呼ばれることになる。new_sync_write()は、本質的にはext4_file_write_iter()を呼び出すための関数である。

fs/ext4/file.c
static ssize_t
ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
    struct inode *inode = file_inode(iocb->ki_filp);

    if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
        return -EIO;

#ifdef CONFIG_FS_DAX
    if (IS_DAX(inode))
        return ext4_dax_write_iter(iocb, from);
#endif
    if (iocb->ki_flags & IOCB_DIRECT)
        return ext4_dio_write_iter(iocb, from);
    else
        return ext4_buffered_write_iter(iocb, from);
}

今回は、ページキャッシュのwrite backの概要を知りたいので、ext4_buffered_write_iter()を読む。

fs/ext4/file.c
static ssize_t ext4_buffered_write_iter(struct kiocb *iocb,
                    struct iov_iter *from)
{
// 略
    ret = generic_perform_write(iocb->ki_filp, from, iocb->ki_pos);
// 略

generic_perform_write()は、以下のようになっており、a_ops->write_begin()とa_ops->write_end()に挟まれて、iov_iter_copy_from_user_atomic()が呼び出されている。

mm/filemap.c
ssize_t generic_perform_write(struct file *file,
                struct iov_iter *i, loff_t pos)
{
    struct address_space *mapping = file->f_mapping;
    const struct address_space_operations *a_ops = mapping->a_ops;
// 略
    do {
// 略
        status = a_ops->write_begin(file, mapping, pos, bytes, flags,
                        &page, &fsdata);
        if (unlikely(status < 0))
            break;

        if (mapping_writably_mapped(mapping))
            flush_dcache_page(page);

        copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);
        flush_dcache_page(page);

        status = a_ops->write_end(file, mapping, pos, bytes, copied,
                        page, fsdata);
// 略

上の処理の概要は以下のとおりである。

  • a_ops->write_begin()ではページキャッシュを取得する。
  • iov_iter_copy_from_user_atomic()では、ユーザ空間から渡された書き込みデータを該当ページキャッシュにコピーする。この時点では、RAMからRAMへのコピーである。
  • a->ops->write_end()では、主に該当ページキャッシュの状態がダーティーに遷移したときの処理を行う。実は、この中でwrite backの処理をWorkqueue経由で依頼する。

write_beginおよびwrite_end

write_begin, write_endについては、一番シンプルそうな関数を選んで読むことにする。

fs/ext4/inode.c
static const struct address_space_operations ext4_aops = {
    .readpage       = ext4_readpage,
    .readahead      = ext4_readahead,
    .writepage      = ext4_writepage,
    .writepages     = ext4_writepages,
    .write_begin        = ext4_write_begin,
    .write_end      = ext4_write_end,
    .set_page_dirty     = ext4_set_page_dirty,

write_begin

write_beginから読む。先に書いたとおり、ページキャッシュの取得をしている。ページキャッシュがない場合、ストレージ(バッキングストア)から読み出してFillするか、0-fillされたページを用意する。いずれにせよ、ページキャッシュとして何らかのメモリページを渡す。

今回は「ページキャッシュのwrite backの概要」が知りたいので、ページキャッシュを取得する処理の詳細は割愛する。

static int ext4_write_begin(struct file *file, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned flags,
                struct page **pagep, void **fsdata)
{
// 略
retry_grab:
    page = grab_cache_page_write_begin(mapping, index, flags);
    if (!page)
        return -ENOMEM;
// 略
#ifdef CONFIG_FS_ENCRYPTION
// 略
#else
    if (ext4_should_dioread_nolock(inode))
        ret = __block_write_begin(page, pos, len,
                      ext4_get_block_unwritten);
    else
        ret = __block_write_begin(page, pos, len, ext4_get_block);
#endif
    if (!ret && ext4_should_journal_data(inode)) {
        ret = ext4_walk_page_buffers(handle, page_buffers(page),
                         from, to, NULL,
                         do_journal_get_write_access);
    }

write_end

先に書いたとおり、write_end()では、ダーティな状態への遷移を主に取り扱っている。

fs/ext4/inode.c
static int ext4_write_end(struct file *file,
              struct address_space *mapping,
              loff_t pos, unsigned len, unsigned copied,
              struct page *page, void *fsdata)
{
// 略
    if (inline_data) {
// 略
    } else
        copied = block_write_end(file, mapping, pos,
                     len, copied, page, fsdata);

block_write_end()から、__block_commit_write() --> mark_buffer_dirty() --> __mark_inode_dirty()のルートをたどる。

fs/buffer.c
int block_write_end(struct file *file, struct address_space *mapping,
            loff_t pos, unsigned len, unsigned copied,
            struct page *page, void *fsdata)
{          
    // 略
    /* This could be a short (even 0-length) commit */
    __block_commit_write(inode, page, start, start+copied);
    // 略

__mark_inode_dirty()は以下のとおりであり、wb_wakeup_delayed()を呼ぶ。

fs/fs-writeback.c
void __mark_inode_dirty(struct inode *inode, int flags)
{
// 略
    if ((inode->i_state & flags) != flags) {
// 略
        if (!was_dirty) {
// 略
            if (wakeup_bdi &&
                (wb->bdi->capabilities & BDI_CAP_WRITEBACK))
                wb_wakeup_delayed(wb);
            return;
        }
    }
// 略

また、wb_wakeup_delayed()は以下のようになっており、queue_delayed_work()を通して、dirty_writeback_internal * 10 ミリ秒後に起動するようにWorkqueueに依頼する。

mm/backing-dev.c
void wb_wakeup_delayed(struct bdi_writeback *wb)
{
    unsigned long timeout;

    timeout = msecs_to_jiffies(dirty_writeback_interval * 10);
    spin_lock_bh(&wb->work_lock);
    if (test_bit(WB_registered, &wb->state))
        queue_delayed_work(bdi_wq, &wb->dwork, timeout);
    spin_unlock_bh(&wb->work_lock);
}

デフォルトでは、dirty_writeback_internal は500である。よって、500 * 10ミリ秒 = 5秒がデフォルトの遅延時間となる。

mm/page-writeback.c
unsigned int dirty_writeback_interval = 5 * 100; /* centiseconds */

write back処理

先のqueue_delayed_work()で遅延処理されるのは、以下のとおりwb_workfnである。

mm/backing-dev.c
static int wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi,
           gfp_t gfp)
{
// 略
    INIT_DELAYED_WORK(&wb->dwork, wb_workfn);
// 略

wb_workfn()は以下の関数で、通常想定されるルートでは、wb_do_writeback()を呼び出してwrite backを行う。

割愛するが、最終的にはwb_do_writeback()からいくつかの関数呼び出しを経てdo_writepages()が呼ばれ、その中でページャ経由でのWriteが行われる。

fs/fs-writeback.c
void wb_workfn(struct work_struct *work)
{   
    struct bdi_writeback *wb = container_of(to_delayed_work(work),
                        struct bdi_writeback, dwork);
// 略
    current->flags |= PF_SWAPWRITE;

    if (likely(!current_is_workqueue_rescuer() ||
           !test_bit(WB_registered, &wb->state))) {
        /*
         * The normal path.  Keep writing back @wb until its
         * work_list is empty.  Note that this path is also taken
         * if @wb is shutting down even when we're running off the
         * rescuer as work_list needs to be drained.
         */
        do {
            pages_written = wb_do_writeback(wb);
            trace_writeback_pages_written(pages_written);
        } while (!list_empty(&wb->work_list));
    } else {
// 略
    }

    if (!list_empty(&wb->work_list))
        wb_wakeup(wb);
    else if (wb_has_dirty_io(wb) && dirty_writeback_interval)
        wb_wakeup_delayed(wb);

    current->flags &= ~PF_SWAPWRITE;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

第一回 Flutter + VScode でLinuxアプリを作成する(環境構築編)

はじめに

全3回に分けFlutterでLinuxのGUIアプリを作成する手順をまとめています。
開発環境はVScodeを使用し、タイマーアプリを作成します。

第一回 環境構築編(今回はここ)
第二回 画面作成編
第三回 完成編

今回はFlutterのインストールからサンプルアプリの実行までの記事です。

Flutterを初めて数日の完全初心者が記事を書いていますので、間違いがありましたらご指摘・コメントいただけると助かります。

環境

Ubuntu(18.04.1)
Flutter(2.0.1)
VScode(1.42.1) 導入済み

1.Flutterのインストール

基本的に公式の方法を参考に進めていきます。

https://flutter.dev/docs/get-started/install/linux
からFlutter SDKをダウンロードします。

ダウンロードしたものを展開します。
Flutterのバージョンはダウンロードしたものに合わせてください。

$ mkdir  ~/development
$ tar xf ./flutter_linux_2.0.1-stable.tar.xz -C ~/development

環境パス

~/.bashrcを開き最後にパスを追加します。

$ vi ~/.bashrc

export PATH="$PATH:~/development/flutter/bin"

環境パスの情報を更新します。

$ source ~/.bashrc

パスが通ったことを確認します。

$ flutter --version
Flutter 2.0.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision c5a4b4029c (2 days ago) • 2021-03-04 09:47:48 -0800
Engine • revision 40441def69
Tools • Dart 2.12.0

2.ビルド環境作成

アプリを作成するのに必要なものをインストールします。

$ sudo apt install clang curl pkg-config ninja-build cmake libgtk-3-dev libblkid-dev liblzma-dev unzip

FlutterのビルドターゲットをLinuxにします。

$ flutter config --enable-linux-desktop

環境に問題ないかを以下のコマンドで確認できます。

$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.0.1, on Linux, locale ja_JP.UTF-8)
[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from:
      https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK
      components.
      (or visit https://flutter.dev/docs/get-started/install/linux#android-setup
      for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.

[✗] Chrome - develop for the web (Cannot find Chrome executable at
    google-chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[✓] Linux toolchain - develop for Linux desktop
[!] Android Studio (not installed)
[✓] VS Code (version 1.42.1)
[✓] Connected device (1 available)

! Doctor found issues in 3 categories.

3.プロジェクトの作成・実行

プロジェクトを作成します。

$ mkdir app
$ cd app
$ flutter create .

appがプロジェクト名です。プロジェクト名によっては、以下のようなエラーになります。
その場合は、名前を変えてください。(原因がよくわからないのでわかる方は教えていただけると助かります。)

"XXXXXX" is not a valid Dart package name.
See https://dart.dev/tools/pub/pubspec#name for more information.

作成したプロジェクトをVScodeで開くと以下のようになります。
01.JPG

VScodeの設定[オプション]

Flutterの拡張機能があるので、VScodeにインストールします。
02.JPG

実行

以下のコマンドで実行します。

$ flutter run -d linux

03.JPG

Flutterにはホットリロードという機能があり、実行中にソースコードを変更・保存した後、ターミナル上でrを行うことで即座に変更した内容が画面に反映されます。

リリースビルド

$ flutter build linux

build/linux/release/bundle/に出力されます。

終わりに

思ったよりも簡単に環境を作成できました。
次回からUIまわりの作成に入りますので、よければぜひ読んでください。

最後まで読んで下さりありがとうございました。
次回またお会いしましょう。

参考

Flutter公式サイト
[Flutter] デスクトップ 環境構築 for Linux
Flutter入門[環境構築〜Todoアプリ]L

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PowerShellにPathを永続的に追加する Ubuntu(Linux)版

環境

Ubuntu 20.04 LTS
PowerShell 7.1.2

方法

Microsoft.PowerShell_profile.ps1
$Env:PATH += ":追加したいパス"

上記の記述を ~/.config/powershell/Microsoft.PowerShell_profile.ps1 に追加する。
デフォルトでは powershellディレクトリも Microsoft.PowerShell_profile.ps1も存在しないので、新規作成する。
LinuxではPathの区切り文字はコロン(:)で、 追加したいパス の前に付ける。

参考にしたウェブサイト(Widnows 10 環境)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UbuntuにAndroid Studioをインストール

UbuntuにAndroid Studioをインストール

環境

・Ubuntu 18.04.05
・Android Studio 4.1.2 for Linux 64-bit

インストール

下記のサイトに従う。
https://developer.android.com/studio/install?hl=ja

事前準備

64BitのUbuntuのためライブラリをapt

$ sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386

本体のダウンロード&インストール

以下から最新のAndroidStudioをダウンロード(執筆時点は4.1.2)
https://developer.android.com/studio?hl=ja

Archive Managerを使用して、圧縮ファイルを解凍する。
今回は個人仕様であるため、local下に展開したフォルドごと移動する。
(解凍先はArchibe Managerで指定できる。今回はDownloads直下で解凍した。)

$ mv ~/Downloads/android-studio /usr/local/

実行

”android-studio”を移動した場所に移動し、studio.shを実行する。

$ cd /usr/local/android-studio
$ sh ./bin/studio.sh 

設定ファイルをImportするか聞かれるが、今回始めてAndroidStudioを使用するためSkip。
datashareするかはお好みで。

Setup Wizardが実行するため、設定を確認する。
Custom設定を選んでみたが、基本的に変更せずにポチポチしていけば問題なさそう。

最後にSDK等のコンポーネントがダウンロード(5分程度)したら終了。

今後起動する際は、以下のコマンドで起動できる。

$ sh /usr/local/android-studio/bin/studio.sh 

最後に

以下にある動画をスクリプト化しただけの記事でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Linuxにおける権限に関するまとめ(`chmod 777`は何をしているのか)

chmod 777 <ファイル名/ディレクトリ名>というコマンドが権限を付与するコマンドであることは初心者のエンジニアの方もご存知かもしれません。
ですが、この777という数字、具体的にどういう意味なのか、はっきりと理解できていますでしょうか。

「全権限を付与するということは知っている、、、」という方(過去の自分)向けに、Linuxの権限の意味についてまとめました。

パーミッション(権限)について

ls -lというコマンドを叩くと下記のようにディレクトリ内のファイルを確認することができます。

drwxr-xr-x  2 toshiokun  staff  64  3  5 09:25 dir1
-rw-r--r--  1 toshiokun  staff   0  3  5 09:25 file1
-rw-r--r--  1 toshiokun  staff   0  3  5 09:25 file2

右側のdir1 file1 file2 はそれぞれディレクトリ名とファイル名を指していますが、左側のdrwxr-xr-xは「何のことやら」となっている方もいるかと思います。
実はこのdrwxr-xr-xの部分が「誰に何の権限を渡しているのか」というパーミッションを表している表記になります。

Linux内のパーミッション(権限)の定義について

パーミッション(権限)には下記のような概念が存在します。

  • 誰に
    • オーナー
    • グループ
    • その他のユーザー
  • 何に対して
    • ファイル
    • ディレクトリ
  • どの権限を渡すか
    • read(読み取り)権限
    • write(書き取り)権限
    • execute(実行)権限

それぞれについて詳細を説明していきます。

オーナーとグループ(誰に権限を渡すのか)について

ファイルとディレクトリにはそれぞれ「オーナー」と「グループ」が存在します。
「オーナー」は文字通り、対象の所有者のことを指します。

「グループ」についてですが、Linuxのユーザーは「グループ」という単位でひとくくりにすることができます。
ファイルとディレクトリは、オーナーとは別に、グループという単位で与える権限を定義することができるのです。

【参考】グループを確認するコマンド
groups <user_name>

権限の意味について

権限には「読み取り権限」「書き取り権限」「実行権限」がありますが、権限の意味は「ファイルに対して」と「ディレクトリに対して」で意味が少し異なるので注意が必要です。

ファイル ディレクトリ
read(読み取り)権限 ファイルの中身を閲覧できる ディレクトリ内に配置されているファイル一覧を取得できる
write(書き取り)権限 ファイルの中身を編集できる ディレクトリ内に配置されているファイルを作成/削除できる
execute(実行)権限 ファイルの中身を実行できる(シェルスクリプト等の場合有効) ディレクトリをカレントディレクトリにできる

権限の表記について

上記の定義を踏まえて、drwxr-xr-xという表記は、「誰に」「何に対して」「どの権限を渡すか」という権限の内容を簡潔に表しているものになります。
drwxr-xr-xの部分は下記のように意味を分解できます。

d rwx r-x r-x
対象が「ディレクトリ」か、「ファイル」か オーナーのパーミッション グループのパーミッション その他のユーザーのパーミッション

対象の表示

  • dと表示される場合
    • ディレクトリを指す
  • -と表示される場合
    • ファイルを指す

パーミッションの表示

  • rと表示される場合
    • read(読み取り)権限があることを指す
  • wと表示される場合
    • write(書き取り)権限があることを指す
  • xと表示される場合
    • execute(実行)権限があることを指す
  • -と表示される場合
    • 該当の権限がないことを指す

つまりdrwxr-xr-xは何を指している?

上記のことを踏まえると、drwxr-xr-x

  • 何に対して
    • ディレクトリであるdir1に対して
  • 誰に
    • オーナーに
      • 「読み取り権限」「書き取り権限」「実行権限」を渡す
    • グループに
      • 「読み取り権限」「実行権限」を渡す
    • その他のユーザーに
      • 「読み取り権限」「実行権限」を渡す

ということを意味することになります。

chmod 777 <ファイル名/ディレクトリ名>というコマンドについて

最後に、導入で話をしたchmod 777 <ファイル名/ディレクトリ名>というコマンドの777について説明をして、この記事を終わりたいと思います。
777

7 7 7
オーナーのパーミッション グループのパーミッション その他のユーザーのパーミッション

と、それぞれの数字が、「オーナーのパーミッション」「グループのパーミッション」「その他のユーザーのパーミッション」を表しています。
7はrwxの別表記だと言い換えてもいいでしょう。

この数字は、下記のように2進数ごとに権限を割り当て、足し合わせた数値で表現することで、渡す権限を表現しています。

4 2 1
read(読み取り)権限 write(書き取り)権限 execute(実行)権限
具体例
7 = 4(読み取り権限) + 2(書き取り権限) + 1(実行権限)
5 = 4(読み取り権限) + 1(実行権限)
3 = 2(書き取り権限) + 1(実行権限)

なので

  • chmod 777なら、すべてのユーザーに「読み取り権限」「書き取り権限」「実行権限」を渡す
  • chmod 755なら、オーナーに「読み取り権限」「書き取り権限」「実行権限」を渡し、オーナー以外のユーザーには「読み取り権限」「実行権限」を渡す

という意味になります。

まとめ

今回はchmod 777 <ファイル名/ディレクトリ名>というコマンドの解説をしました。
このコマンドは本番環境などでアプリケーションの運用をするときだけでなく、ローカル環境の構築でも使用することも多いと思います。

何となくコマンドを叩いていた方がしっかりと意味を理解して、使いこなすことができる手助けになれば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

lap-top(iiyamaPC)にArchLinux入れてみた

0. 前書き

私事ですが、最近lap-topを持ち運ばなくてはならないことになってしまった。しかも自分的にはそこそこ大きい企業の開発研究で、、、でも自分lap-top持ってなかったので新しく買うことになったわけです。そこでOS入ってないlap-top(iiyamaPC)を購入し、archLinuxをインストールしました。ただし、現在「iiyamaPC」はOSなし構成は選択できないようです。悲しみ、、、

構成

ちなみに当方が購入したPC構成は以下のとおりです。

項目 構成
CPU intel i3-10100
メモリ ddr4-2666 16GB(8GB*2)
GPU GeForce MX350 2GB
ストレージ(メイン) SSD(PCIe) 256GB
ストレージ(サブ) SSD(sata) 512GB

そしてこの記事でま目指すシステム構成は以下のとおりです。

項目 構成
OS archLinux
ブートローダー GRUB
ディスプレイマネージャ LightDM
ウィンドウマネージャ Xfce4

その他、lap-topなのでセキュリティ関係はしっかりとしたいので、そのへんの構成は以下の感じ。

ストレージの暗号化

archLinuxに標準搭載の「dm-crypt」を用いて、ストレージを暗号化します。めんどくさいので、メインストレージは「/boot」「/」の2つのみのパーティションにしてます。そのうち「/」のみ暗号化します。起動時にパスワードを入力してマウントできるようにします。サブストレージはユーザースペースディレクトリにマウントできるようにして、復号化には乱数ファイルをメインストレージのどこかに保存します。そうすることによって、自身の個人的なデータはメインストレージのファイルがないと中身が見れないようにします。

ファイヤーウォール

archLinuxにファイヤーウォールは標準で有効になっていません。なので有効化しましょう。一応「iptables」が標準で入っていますが、ルール作成が面倒なのでさくっと設定できるサービスをインストールすることをおすすめします。今回は「firewalld」をインストールします。

ウイルススキャン

ウイルスファイルをスキャンする機能もarchLinuxには標準搭載していません。なのでそれもインストールしましょう。今回は「ClamAV」をインストールします。本来はWindows向けのマルウェア検出ソフトなので、linux系には意味がないと思われるかもしれません。ですが、ローカルネットにWindowsがあるような環境では間接的に感染させてしまうかもしれないので有効です。チームで開発する場合には、自身のセキュリティだけでなく周りのことも気にかけましょう。

ファイル保護

ファイルの不正な編集やディレクトリへの不正なアクセスを保護する考え方で「任意アクセス制御」「強制アクセス制御」があります。任意アクセス制御は標準で搭載されていますが、強制アクセス制御は導入されていません。なので、この記事では「SELinux」をインストールします。

とりあえずセキュリティ的にはこんなところ。あとの細かいところはインストール手順で説明します。

1. インストール手順

さて、やっと本題です。基本的にはインストール手順はここに書いてあるのですが、参考までに。また、linuxにはじめてさわる方はarchlinuxはおすすめしません。おとなしくubuntu等から始めましょう。CLI操作に慣れていないとかなりきついです。

インストールディスクの作成

まずはインストールメディアを入手します。ここにアクセスし、最新のisoファイルを入手してください。そしてWindowsでは「ブータブルUSB作成ツール」で作成してください。Macやlinuxでは以下のようにコマンドで作成できます。

$ sudo dd bs=1M if=path/to/iso of=/dev/sdX

sdXの部分には、インストールするUSBを指定してください。

BIOS設定

まずBIOSの設定画面に入ってください。そして以下の設定項目を探し、パラメータを更新してください。インストールUSBを挿した状態で入っておくとブートデバイスを指定できるので、この時点で挿しておくといいでしょう。

設定項目 パラメータ
ブート方式 UEFI
セキュアブート 無効
ブートデバイス インストールUSB

起動

インストールUSBを挿した状態で起動し、archLinuxのブート画面で一番上の選択肢を選択してインストールシェルを起動します。

CLIでの操作

ここから先はコンソールで設定することになります。インストールシェルでは「Zsh」がデフォルトで有効になっていて、コマンド補完が強力に動作します。なので、長いコマンドなどは最初の数文字打って「Tab」キーを押すと補完されます。便利なので使いましょう。コマンドだけでなく、ディレクトリやファイルも補完してくれるので是非。

キーボードレイアウトの指定

キーボードのレイアウトを変更します。おそらく日本語の標準キーボードだと思うので、レイアウトに「jp106」を指定。

$ loadkeys jp106

起動モードの確認

一応起動方式が「UEFI」であるかを確認するために、以下のコマンドを実行。もしディレクトリが存在しないと表示されたら、「MBR」で起動されていますので、BIOSの設定を確認してブート方式がUEFIになっているか確認してください。

$ ls /sys/firmware/efi/efivars

ネットワークへの接続

インストールメディアにはインストールデータは入ってません。いや入ってはいるのですが、そこからコピーするのではなく、ネットワークからインストールします。なのでネットに接続しなければなりません。

有線接続の場合

PCにLANポートがある場合はそこにLANを挿して、以下のコマンドで自分がIPアドレスをもらえているか確認してください。

$ ip a

出力結果のうち、「lo」から始まる段はあまり気にせず。「eth~」か「enp~」から始まる段は有線接続のネットワークインターフェースの出力です。確認すべきは「inet」から始まる行に何かしらのアドレスが表示されていればIPアドレスが取得できています。「wlp~」か「wlan」から始まる段は無線接続のネットワークインターフェースの出力で、内容の見方は無線と同じです。

ルーターがDHCPに対応していない場合

もしルーターがDHCPに対応していない場合IPが自動でもらえません。なので手動で設定しましょう。ここを参考にしてください。ただしサブネットマスクなどが不明の場合、システム管理者に問い合わせてください。

$ ip link set eth0 up
$ ip addr add 192.168.1.2/24 broadcast 192.168.1.255 dev eth0
$ ip route add default via 192.168.1.1

1行目はネットワークインターフェイス起動しています。「eth0」はネットワークインターフェースを指定しますが、「eth~」か「enp~」で始まることが多いです。上記の「有線接続の場合」のコマンドを実行して確認してください。

2行目は自分にIPアドレスを指定し、それをローカルネットに通知しています。ちなみにコマンド引数の「192.168.1.2/24」の/より前がIPアドレス、後がサブネットマスクです。IPアドレスはローカルネット上で重複は許されません。なので手動で設定するするときにはちゃんと確認しましょう。サブネットマスクは、同じローカルネットでは一致していないといけません。なのでIPアドレスと同じく確認しましょう。

3行目はデフォルトのゲートウェイを指定しています。グローバルネットに接続するための設定です。

無線接続の場合

archLinuxのインストールメディアには無線接続ためのサービスで「iwd」が入っています。なのでここを参考に無線LANに接続します。

$ iwctl  #無線設定用シェルを起動
[iwd]# device list  #ワイヤレスデバイス名を確認します
[iwd]# station DEVICE scan  #確認したデバイス名でネットワークをスキャンします
[iwd]# station DEVOCE get-networks  #利用可能なネットワークを確認します
[iwd]# station DEVICE connect SSID  #SSIDを指定してアクセスします。

パスフレーズが設定されている場合、パスフレーズを要求されますので、入力します。

ルーターがDHCPに対応していない場合

無線接続の場合も有線接続と同様、DHCPが有効になっていない場合、手動でIPアドレスを指定しなくてはなりません。ここを参考に設定していきます。
まずテキストエディタで「/var/lib/iwd/spaceship.psk」を編集します。ここでテキストエディタは「nano」を使います。

$ nano /var/lib/iwd/spaceship.psk

そしてファイルを以下のように編集します。

/var/lib/iwd/spaceship.psk
[IPv4]
Address=192.168.1.10
Netmask=255.255.255.0
Gateway=192.168.1.1
Broadcast=192.168.1.255
DNS=192.168.1.1

もし自身でネットワークを設定していない場合はネットワーク管理者に問い合わせてください。

接続の確認

以下のコマンドで、ネットワークへの接続を確認します。ちゃんとパケットが帰ってきていれば大丈夫。

$ ping archlinux.jp

システムクロックの更新

システムクロックを正確にしないと、たまにアクセスを拒否される時があります。なので「timedatectl」サービスを使ってシステムクロックを更新します。

$ timedatectl set-ntp true

パーティションの作成

今回のシステムでは暗号化をする関係上、設定が面倒になるので「tmp」や「var」等のパーティションは設定しません。「swap」すら用意しません。スワップファイルも設定しません。というかメモリ16GBあってサーバーでもないのにスワップあっても、パフォーマンスの向上を見込めないし、SSDの寿命を縮めるだけなのでいらないです。なので以下のような構成になります。

パーティション 容量 タイプ(タイプコード)
/dev/nvme0n1p1 256MB EFI System partition(ef00)
/dev/nvme0n1p2 残り全部 dm-crypt(8308)

まずはメインストレージのパーティションを行います。

$ gdisk /dev/nvme0n1  #gdiskでnvmeディスクを指定

~~~~ 省略 ~~~~

Command (? for help): o  # 新規のGPTを作成する
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): Y # 作成して大丈夫?って聞かれてるだけなのでYを入力

Command (? for help): n  #新規パーティション作成
Partition number (1-128, default 1):   #そのままEnter
First sector (~省略~):  #そのままEnter
Last sector (~省略~): +256MB  #サイズを256MBに指定
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): ef00  #パーティションタイプを「EFI system partition」に指定
Changed type of partition to 'EFI system partition'

Command (? for help): n  #新規パーティション作成
Partition number (1-128, default 2):   #そのままEnter
First sector (~省略~):  #そのままEnter
Last sector (~省略~):  #そのままEnter
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 8308  #パーティションタイプを「Linux dm-crypt」に指定
Changed type of partition to 'Linux dm-crypt'

Command (? for help): w  #変更を保存

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING PARTITIONS!!

Do you want to proceed? (Y/N): Y  #変更保存しちゃって大丈夫?って聞かれてるだけなのでYを入力

これでメインストレージはパーティショニングが終了。
次にサブストレージのパーティションを作成します。サブストレージは単一パーティションのみで「/home」にマウントします。パーティションタイプを「dm-crypt」にする以外はデフォルトでOK。

$ gdisk /dev/sda  #gdiskでsdaディスクを指定

~~~~ 省略 ~~~~

Command (? for help): o  # 新規のGPTを作成する
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): Y # 作成して大丈夫?って聞かれてるだけなのでYを入力

Command (? for help): n  #新規パーティション作成
Partition number (1-128, default 1):   #そのままEnter
First sector (~省略~):  #そのままEnter
Last sector (~省略~):  #そのままEnter
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 8308  #パーティションタイプを「Linux dm-crypt」に指定
Changed type of partition to 'Linux dm-crypt'

Command (? for help): w  #変更を保存

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING PARTITIONS!!

Do you want to proceed? (Y/N): Y  #変更保存しちゃって大丈夫?って聞かれてるだけなのでYを入力

これでサブストレージもパーティショニング終了。

メインストレージの暗号化

先ほど作成したパーティションのうち「/dev/nvme0n1p2」をパスフレーズによって暗号化します。サブストレージは後程キーファイルによって暗号化するのでここでは暗号化しません

$ cryptsetup -v luksFormat /dev/nvme0n1p2

~~~~  省略 ~~~~
Are you sure? (Type 'yes' in capital letters): YES  #諸々了承したら大文字で「yes」と入力
/dev/nvme0n1p2のパスフレーズを入力して下さい:  #パスフレーズを入力してEnter
同じパスフレーズを入力して下さい:  #同じパスフレーズを入力してEnter
~~~~ 省略 ~~~~

$ cryptsetup open /dev/nvme0n1p2 crypt-root  #暗号化デバイスを「crypt-root」として接続
/dev/nvme0n1p2のパスフレーズを入力してください:  #パスフレーズを入力してEnter

~~~~ 省略 ~~~~

メインストレージのフォーマット

メインストレージのフォーマットを行います。フォーマと形式は以下の通り。

ディスク フォーマット
/dev/nvme0n1p1 FAT32
/dev/mapper/crypt-root ext4

なお「/dev/nvme0n1p2」を指定してフォーマットしないように注意しましょう。

$ mkfs.vfat -F32 /dev/nvme0n1p1  #FAT32を指定してフォーマット
$ mkfs.ext4 /dev/mapper/crypt-root  #ext4を指定してフォーマット

メインストレージのマウント

メインストレージをマウントします。

$ mount /dev/mapper/crypt-root /mnt  #「/mnt」に「/dev/mapper/crypt-root」をマウント
$ mkdir /mnt/boot  #「boot」ディレクトリを作成
$ mount /dev/nvme0n1p1 /mnt/boot  #「/mnt/boot」に「/dev/nvme0n1p1 」をマウント

コアパッケージのインストール

必要最低限のパッケージをインストールします。

$ pacstrap /mnt base base-devel linux linux-firmware 

fstabの生成

fstabを生成し、自動マウントできるようにします。

$ genfstab -U /mnt >> /mnt/etc/fstab

chroot

新しくインストールした環境に仮想的にログインします。

$ arch-chroot /mnt

タイムゾーン

タイムゾーンを日本に設定します。

$ ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ hwclock --systohc

ロケールの設定

/etc/locale.gen を編集して、「en_US.UTF-8 UTF-8」と「ja_JP.UTF-8 UTF-8」をアンコメント(行頭の#を消去)します。そして以下のコマンドを実行。

$ locale-gen  #ロケールの生成
$ echo 'LANG=en_US.UTF-8' > /etc/locale.conf  #ロケールの設定
$ echo 'KEYMAP=jp106' > /etc/vconsole.conf  #仮想コンソールのキーボードマップ設定永続化

rootパスワードの変更

rootパスワードがない状態は非常に危険なので、変更しましょう。

$ passwd
新しいパスワードを入力してください:  #設定したいパスワードを入力してEnter
新しいパスワードを再入力してください:  #もう一度パスワードを入力してEnter

ブートローダーの設定

さてここからブートローダーの設定をしていきます。

GRUBのインストール

まずはブートローダー関係のパッケージをインストールします。今回の環境では「GRUB」を導入します。「UEFI」方式のブートに対応していて、カーネルパラメータが設定しやすい。(気がする)またGEUBでUEFIブートに必要なパッケージとして「EFI boot manager」もインストールします。

$ pacman -S grub efibootmgr

マイクロコードのインストール

マイクロコードをインストールします。マイクロコードとは、CPUのファームウェアのようなもので、これを入れておかないとシステムが不安定になる場合があるらしい。

インテル系のCPUの場合
$ pacman -S intel-ucode
AMD系CPUの場合
$ pacman -S amd-ucode

mkinitcpioの設定

デバイスの暗号化をしているため、起動時にパスコードを要求できるようにします。これをしないとブートできても暗号化が解除できないので使えるようになりません。ここを参考に、まず「/etc/mkinitcpio.conf」を編集します。「keyboard」「keymap」「encrypt」を追加しています。ちなみに記述した順番に読み込まれるので、この順番に記述してください。

/etc/mkinitcpio.conf
~~~~ 省略 ~~~~

HOOKS="base udev autodetect keyboard keymap consolefont modconf block encrypt lvm2 filesystems fsck"

~~~~ 省略 ~~~~

編集したのち、以下のコマンドを実行してmkinitcpioを再生成します。

$ mkinitcpio -P linux

GRUBカーネルパラメータの編集

起動時にどのデバイスの暗号化を解除させるかを指定し、mapperを命名します。「/etc/mkinitcpio.conf」を編集し、以下のようなカーネルパラメータを指定してください。

~~~~ 省略 ~~~~

GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet cryptdevice=/dev/nvme0n1p2:crypt-root root=/dev/mapper/crypt-root"

~~~~ 省略 ~~~~

ブートローダーのインストール

次にブートローダーをインストールし、設定ファイルを生成します。

$ grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub --boot-directory=/boot--debug
$ grub-mkconfig -o /boot/grub/grub.cfg

暗号化デバイスの自動マウント設定

暗号化したディスクを起動時に自動マウントするために、「/etc/crypttab」を編集します。

~~~~ 省略 ~~~~
crypt-root /dev/nvme0n1p2 none luks,timeout=180

その他パッケージのインストールと設定

ここからは最低限動かすのに必要(であろうものも含めて)なパッケージをインストール。

  • NetworkManager・・・ネットワーク設定ツール。有線接続も無線接続もちゃんとできて、VPNなどのプラグインもあるので結構便利。
  • firewalld・・・ファイヤーウォール。
  • nano・・・コンソールテキストエディタ。初心者に比較的優しい。
  • gdisk・・・GPT用のディスクパーティション作成ツール。
$ pacman -S networkmanager firewalld nano gdisk

インストールしたのち、起動時に有効化するようにします。

$ systemctl enable NetworkManager
$ systemctl enable firewalld

再起動

再起動して、ブートが完了するか確認してください。

$ exit  #arch-chrootから脱出
$ umount -R /mnt  #ディスクをアンマウント
$ reboot  #再起動する。

再起動時にインストールUSBを外し、BIOS画面に移行し、起動ディスクをインストールしたメディアに設定。

ここまででいったん記事は終わります。GUI導入からはまた後日書きたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む