はとのーと

エジソンノート(アイデア、思い付き、メモ)として使っています。誰かの役に立つかもしれないので公開しています。

LXC上にDebianをインストール

設定の備忘録。 DebianのバージョンはBullsEye (11)。 LXC/LXDの設定は終わっている前提。 関連ページ: LXC/LXDについてのメモ

以下は断りのない場合はすべてroot権限で実行。

コンテナを作成する

ホスト上から lxc launch images:debian/11/amd64 deb1 でインストール。 コンテナ名は deb1

lxc exec deb1 -- /bin/bash でコンテナの中に入る。

以下、コンテナ内での操作。

近くのリポジトリを設定する

/etc/apt/sources.list の内容を Debian JP Project - ミラーサイトについて に書いてある内容に変更。

deb http://ftp.jp.debian.org/debian/ bullseye main contrib non-free
deb http://ftp.jp.debian.org/debian bullseye-updates main contrib

netselect-apt を入れてさらに近いミラーサイトを調べる。

$ sudo apt update
$ sudo apt install netselect-apt
$ sudo netselect-apt --country japan
...
Of the hosts tested we choose the fastest valid for http:
        http://mirrors.xtom.jp/debian/

自分の場所からはxTomが近いので /etc/apt/sources.list を次のように変更。

deb http://mirrors.xtom.jp/debian/ bullseye main contrib non-free
deb http://mirrors.xtom.jp/debian bullseye-updates main contrib
一般ユーザを作成する

useradd -m -U paz でユーザを作成。 -m はホームディレクトリの作成、-U は同名グループの作成。

password paz でパスワードを設定。

usermod -a -G sudo pazsudoグループに追加。

chsh -s /bin/bash paz でログインシェルをBashに変更。

共有設定

ホスト側で lxc config set deb1 raw.idmap 'both 1000 1000' を実行してホストと同じユーザ(1000)でDebianが動くように設定。

ホスト側で lxc config device add deb1 share disk source=/home/foo/share path=/home/foo/share を実行して ~/share 以下をホストとゲストで共有する。

リモートデスクトップで接続できるようにする

apt install xrdp xterm twm でxRDPとxterm、twmをインストール。

ホスト側で lxc config device add deb1 deb1-rdp proxy listen=tcp:192.168.0.4:3389 connect=tcp:0.0.0.0:3389 bind=host で3389ポートをポートフォワード。

RDPで接続するとウィンドウマネージャとしてtwmが動いている画面になる。

デスクトップ環境としてMATEをインストールする

apt install --no-install-recommends task-mate-desktop でMATEデスクトップ環境をインストール。

ユーザのホームディレクトリに以下のファイルを置く。

~/.xsesion:

mate-session

~/.xsessionrc:

export XDG_SESSION_DESKTOP=mate
export XDG_DATA_DIRS=/usr/share/mate:/usr/share/mate:/usr/local/share:/usr/share:/var/lib/snapd/desktop
export XDG_CONFIG_DIRS=/etc/xdg/xdg-mate:/etc/xdg

RDPで接続するとデスクトップ環境としてMATEが動いている画面になる。

その他のアプリをインストール:

  • Brisk Menu (お気に入りつきのメニュー) をインストール - apt install mate-applet-brisk-menu
  • Mozo (MATEメニューエディタ) をインストール - apt install mozo
日本語環境をインストールする

apt install task-japanese で日本語環境をインストール。

dpkg-reconfigure locales を実行し、en_US.UTF-8 UTF-8 のチェックを外し、ja_JP.UTF-8 UTF-8 にチェックを入れる。

apt install task-japanese-desktop をインストール。 日本語入力環境としてUIM+Mozcが入る。

タイムゾーンを設定する

timedatectl set-timezone Asia/Tokyo を実行してローカルタイムを東京にする。

skkをインストールする

日本語入力メソッドとしてskkをインストールする。 すでに uim-mozc が入っているのでUIM上で使う。

apt install uim-skk でインストールし、IME設定からskkに切り替える。

Google日本語入力の変換サーバを利用するために apt install yaskkserv でサーバをインストールする。

/etc/defaults/yaskkserv で以下の行を設定する。

YASKKSERV_BIN="yaskkserv_hairy"
HAIRY_OPTS="${NORMAL_OPTS} --server-completion-test=1 --google-japanese-input=notfound-input-suggest --google-suggest"

UIMの設定画面からskkの変換サーバをlocalhost、ポートを1178にする。

Operaをインストールする
# wgetを取得する
sudo apt install wget

# GPGキーをインポートする
wget -O- https://deb.opera.com/archive.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/opera.gpg

# Operaリポジトリを登録する
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/opera.gpg] https://deb.opera.com/opera-stable/ stable non-free" | sudo tee /etc/apt/sources.list.d/opera.list

# Operaをインストールする
sudo apt update
sudo apt install opera-stable

その後「/etc/apt/souces.list.dリポジトリを登録するか?」と聞いてくるが、上記作業ですでに登録してあるので No を選択する。

VS Codeをインストールする

PGPキーをインポートする。

wget -O- https://packages.microsoft.com/keys/microsoft.asc | sudo gpg --dearmor | sudo tee /usr/share/keyrings/vscode.gpg

リポジトリを登録する。

echo "deb [arch=amd64 signed-by=/usr/share/keyrings/vscode.gpg] https://packages.microsoft.com/repos/vscode stable main" | sudo tee /etc/apt/sources.list.d/vscode.list

VS Codeをインストールする。

sudo apt update
sudo apt install vscode
その他のアプリケーションを入れる

PDP-8についてのメモ

配列名とポインタ変数は相互互換ではない

C言語の配列名とポインタ変数は相互互換ではないことがわかったのでメモ。

ポインタと配列の微妙な関係 - めもめも には char[] で定義した文字列を extern char * で参照すると正しく扱えないと書いてあります。

本当かどうか実験してみました。

実験

次のような3つのファイルを考えます。

main1.c:

#include <stdio.h>

extern char hello[];

int main(void)
{
        puts(hello);
        return 0;
}

main2.c:

#include <stdio.h>

extern char *hello;

int main(void)
{
        puts(hello);
        return 0;
}

sub.c:

const char hello[] = "Hello world.";

sub.c で定義した文字列 hello を読み込んでメインで表示していますが、helloの読み込み方に次の違いがあります。

  • main1.c - extern char hello[]
  • main2.c - extern char *hello

実行します。

main1.c:

$ gcc main1.c sub.c -o main1 && ./main1
Hello world.

main2.c:

$ gcc main2.c sub.c -o main2 && ./main2
Segmentation fault (core dumped)

main2の方だけ Segmentation fault が発生します。 配列名とポインタ変数が互換ではないことがわかりました。

説明

この現象について C FAQ 1 によい説明がありました。

char a[] = "hello"; char *p = "world";

は以下のように表現できるデータ構造を初期化する。

              +---+---+---+---+---+---+
           a: | h | e | l | l | o |\0 |
              +---+---+---+---+---+---+
              +-----+     +---+---+---+---+---+---+
           p: |  *======> | w | o | r | l | d |\0 |
              +-----+     +---+---+---+---+---+---+

x[3]を参照したときに産み出されるコードが、xがポインターか配列 かで違うのだと理解することは大事なことである。上記の宣言を与えられたとして、コンパイラはa[3]という式を見たところで、「a」のところから始めて、そこから3つ進んで、そこにある文字を取り出す、というコードをはきだす。p[3]という式を見ると、「p」に進み、そこに存在するポインターの値を取り出し、ポインターの値に3を加え、 最後にポインターが指す場所から文字を取り出す、というコードをはきだす。

どうやら a はアドレス値(定数)なのでそのまま使え、p は変数であるため中身のアドレスを取り出す必要がある(p 自体のアドレスではない)ということのようです。

確認

実際にそうなっているかアセンブリ言語で確認してみました。

以下のようにすると、それぞれ main1.s, main2.s のアセンブリソースコードが出力されます。

$ gcc -S main1.c
$ gcc -S main2.c

main1.s:

        .file   "main1.c"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    $hello, %edi          # <------
        call    puts
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (GNU) 11.3.0"
        .section        .note.GNU-stack,"",@progbits

main2.s:

        .file   "main2.c"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movq    hello(%rip), %rax       # <------
        movq    %rax, %rdi
        call    puts
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (GNU) 11.3.0"
        .section        .note.GNU-stack,"",@progbits

main1.s の方では movl $hello, %edi で hello のアドレスをそのまま使っているのに対し、main2.s の方では movq hello(%rip), %rax で hello の中身をアドレスとして取り出しています。