Manjaro 0.8.13.1 LXQt を LVM + LUKS + GPT + UEFIインストール

3回失敗したので、メモを兼ねて。

情報は

の2箇所にあるため、これを組み合わせる必要がある。 また、情報の欠如もあるので補足する。

まずはターミナルを起動

$ su -
  manjaro #Password
# gdisk /dev/sda

/dev/sdaがインストール対象ディスクであるとする。 以下オペレーションは

  • o #新しいGPTレベルを作成
  • Y #確認
  • n #新規パーティション (BIOS GRUBのためのもの。なくてもいい?)
  • (enter) #次のパーティション
  • (enter) #フリー部分の先頭
  • +1M # 1MiBのパーティション
  • n #新規パーティション (ESP)
  • (enter) #次のパーティション
  • (enter) #フリー部分の先頭
  • +256M # 256MiBのパーティション
  • n #新規パーティション (/boot)
  • (enter) #次のパーティション
  • (enter) #フリー部分の先頭
  • +512M # 512MiBのパーティション
  • n #新規パーティション (LVM)
  • (enter) #次のパーティション
  • (enter) #フリー部分の先頭
  • (enter) # entire disk
  • w #書き込み
  • Y #確認

LVM on LUKSの構築

# cryptsetup luksFormat -y --cipher aes-xts-plain --key-size 512 /dev/sda4
# cryptsetup luksOpen /dev/sda4 sda4_crypt
# pvcreate --dataalignment 1024k /dev/mapper/sda4_crypt
# vgcreate cryptVG /dev/mapper/sda4_crypt
# lvcreate -n root -L 20G cryptVG
# lvcreate -n swap -L 16G cryptVG
# lvcreate -n home -l 100%FREE cryptVG

インストーラはSwapを求めるし、Swap用のボリュームも確保した。

で、

# setup
    1. Set date and time
    1. Partition Hard Drives
    • swap – /dev/mapper/cryptVG-swap
    • / – /dev/mapper/cryptVG-root
    • /home – /dev/mapper/cryptVG-home
    • /boot – /dev/sda3 (EXT3)
    • /boot/efi – /dev/sda2 (VFAT)
    1. Install System
    1. Configure System – mkinitcpio.confについてHOOK行にencrypt lbm2sata filesystemよりも先に記述する。そのままこの画面に留まる
  • タブを開く
  • /install/etc/default/grubGRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=/dev/sda4:cryptVG"と記述する
  • installerの4から離れる
    1. Install bootloader
    • UEFI_x86_64
    • GRUB_UEFI_x86_64
    • フォーマット
    • efivarsが読まれてないよと言われる場合も無視して良い
    • コピーするかと聞かれた場合はYES
    1. Quit
  • 再起動

この作業を繰り返したことで、だいたいLUKSパーティションの起動やUEFIについて仕組みが理解できてよかった。

ただし、実際に動くかどうかを確認できていない。 なぜならば、ハードウェア結局UEFIをサポートしていなかったからだ。どうりで失敗するわけだ。

Btrfsのバックアップがうまくいかない

sshの問題

「sshdだとダメなのに、sshd -d(デバッグモード)では通る!!」 と言っていた問題は、yum update -yしたあとで再起動したら解決した。 意味不明だ。

send/receiveはよく止まる

2.79TiBに達した時に、send側コンピュータが停止してしまう。 なお、スナップショットの削除を行って再びためすと、さらに短く失敗するようになる。

最初はオーバーヒートかと思ったのだが、2.79TBで止まる、ということが共通しているため、問題があるように疑われる。

これで代替手段というと、スクリプトを組むしかないか。 それなりに複雑なものになりそうだ。もっとも、btrfsが集中的なwriteそのものを受け付けないのなら話は別だが、3TB近く書けるのだから、まさか。

rsyncでなくsend/receiveを使うことでBtrfsに戻す

概要

btrfsがrsyncで死んでしまうので、現在はLVM+XFSを使用しているが、いい加減容量は限界近いのでbtrfsに戻す。

rsyncで詰んでしまう以上、rsyncではなく、send/receiveを用いたものとする。 btrfs wikiによれば、rsyncを用いるよりも遥かに高速なのだという。

手順

まずはアンマウント

umount /MirrorSlave

そして、LVMをインアクティブに

vgchange -a n

btrfsを作る

mkfs.btrfs -L MirrorBtr /dev/mapper/btr*

/etc/fstabを編集する

UUID=0123456-7890-acbd-ef01-234567890ab /MirrorRoot           btrfs   noauto,noatime,autodefrag,compress-force=lzo,space_cache,subvol=mirror 0 0

初期化スクリプトを編集する

#!/bin/zsh

typeset -i index=1

for i in /dev/disk/by-id/{ata-foo,ata-bar,ata-baz,ata-quux}
do
#  print $i
  cryptsetup --hash=sha512 --cipher=twofish-xts-plain --offset=0 --key-file=/home/foo/key --key-size=512 open --type=plain "$i" "btrdm_$(printf "%02d" $index)" || exit 1
(( index++ ))
done

mount /MirrorRoot
	
#mount -U 7ebc7d8d-35c6-4d98-8457-3323c242e9fe -o noatime,autodefrag,compress-force=lzo,space_cache,subvol=mirror /MirrorRoot

#pvscan
#vgscan
#lvscan
#vgchange -a y MirrorVG
#lvchange -a y MirrorVG/MirrorLV
#mount -U "0d09b605-a52b-48f4-8ad5-ed26456ab6cd" /MirrorRoot

クライアント側スクリプト。

#!/usr/bin/zsh

notify-send "BtrSnapSync: Woke"

if ! btrfs subvolume snapshot -r /home/foo/share /home/foo/share/snapshots/snapshot-new 
then
  print "BtrSnapSync: **CRITICAL** Failed to create new snapshot"
  exit 2
fi

sync

notify-send "BtrSnapSync: Snapshot."

if [[ -e /home/foo/share/snapshots/snapshot-old ]]
then
  if btrfs send -v -p /home/foo/share/snapshots/snapshot-old /home/foo/share/snapshots/snapshot-new/  | ssh -v -i /root/.ssh/btrsnapsync daisy.local /usr/local/sbin/btrrecv.sh
  then
    notify-send "Send Snapshot."
    btrfs subvolume delete /home/foo/share/snapshots/snapshot-old
    mv /home/foo/share/snapshots/snapshot-new /home/foo/share/snapshots/snapshot-old
    notify-send "Deleted old Snapshot."
  else
    notify-send "Failed to send Snapshot"
    btrfs subvolume delete /home/foo/share/snapshots/snapshot-new
  fi
else
  if btrfs send -v /home/foo/share/snapshots/snapshot-new  | ssh -i /root/.ssh/btrsnapsync daisy.local /usr/local/sbin/btrrecv.sh
  then
    notify-send "Send Snapshot."
    mv /home/foo/share/snapshots/snapshot-new /home/foo/share/snapshots/snapshot-old
    notify-send "Deleted old Snapshot."
  else
    notify-send "Failed to send Snapshot"
    btrfs subvolume delete /home/foo/share/snapshots/snapshot-new
  fi
fi

サーバー側スクリプト

#!/bin/sh
btrfs receive /MirrorRoot && mv /MirrorRoot/snapshot-new /MirrorRooot/snapshot`date +%y%m%d%H%M`

rootのSSH鍵を生成(適宜)

mkdir .ssh
ssh-keygen -f .ssh/snapshot
chmod 700 .ssh
chmod 600 .ssh/*

鍵を転送(適宜)

scp .ssh/snapshot.pub server:.ssh/authorized_keys
ssh server
chmod 600 .ssh/authorized_keys

鍵をコマンドに結びつける

vim .ssh/authorized_keys

sshd_configでforced-commands-only

vim /etc/ssh/sshd_config

挙動

btrfsのsnapshotやsend/receiveについて知識がなかったため、挙動をひとつひとつ確認することにした。

まず、snapshotはディレクトリに見える。 そのディレクトリにはスナップショットの完全なファイルがあるように見える。常時アクセス可能な凍結された状態が存在するわけだ。

そして、スナップショットは元となるボリュームにネストされたサブボリュームになる。 つまり、/fooにマウントされているサブボリュームのスナップショットは、/foo/snapshot1のようになるというわけだ。この外、例えば/barには置けない。

この/foo/snapshot1はmvは可能だが、rmはできない。rmするのであれば、btrfs subvolume deleteでなければならない。

このスナップショットをsendする時、-pオプションがなければそのsnapshotを構成する全体を送信する。あれば、指定されたサブボリューム(マウントされたディレクトリを指定)との差分を送信する。

内容は標準出力に吐かれ、-fオプションで保存することもできるが、それはリダイレクトで保存しても良いようだ。

receiveについても、およそ似たような挙動である。 標準出力から読んで再編成するか、もしくは-fオプションでファイルから編成する。 これは、sharのようなものではなく、編成されるのはスナップショットである。 つまり、snapshot1というsnapshotをreceiveした場合、snapshot1というsnapshotが作られる。

mvで名前が変わった状態で、-pオプション付きで送りつけたsnapshotがどうなるのかは、まだ試していない。

snapshotにロールバックする場合は、マウントポイントの付け替えと、サブボリュームのデリートでよさそうだ。set-defaultが必要か?

多くのスナップショットを維持することでディスク容量やI/Oにどのように影響するのかはわからない。 英語文書を読めばよいのかもしれないが、なかなか大変そうなので、そこには当面手を付ける予定はない。

思わぬつまづき

rootユーザーでRSA鍵でsshログインできないという問題に遭遇した。 一般ユーザーならばできるし、またサーバー側がsshd -dで起動した場合は通る。 デバッグモードなら通るため、メッセージの確認もできない。 かなり困った。

Vine Linux (Seed)とWindows 7のデュアルブート構築と削除

ThinkPad e440がどんどん環境崩壊してしまい、使い物にならないため、再セットアップ。 考えられる原因が

  • TrueCrypt
  • Avast!

のどちらかなので、とりあえず暗号化なしでやってみる。

Windowsの再インストールについては何度か言及しているが、ディスクイメージを保存してあるので、いつもどおりSystemRescueCDでブートし、

ssh foo@192.168.64.128 cat e440.backup/e440.offset.xz | xz -dcv > /dev/sda
ssh foo@192.168.64.128 cat e440.backup/e440.1.xz | xz -dcv > /dev/sda1
ssh foo@192.168.64.128 cat e440.backup/e440.2.{0..8}.xz | xz -dcv > /dev/sda2

パーティションを調整する必要があったので、リサイズ。余計なsda3があったので、それを除去した上で実行する。

Windowsの再構築は結局一日ほどかかったが、環境として導入したのは、

* Immunet Antivirus
* ZoneAlarm Free Firewall
* Bonjour for Windows
* RLogin
* Opera Developer
* SRWare Iron
* Cyberfox Intel
* VLC Media Player
* AIMP
* Audacity
* XnViewMP
* Geany
* サクラエディタ
* Google日本語入力
* Launchy
* Geek Uninstaller
* Sylpheed
* Start Orb Changer
* MacType
* Skype
* Skype Call Video Recorder
* Free Studio
* DR-C125関連

今回は軽さを保つため、ウィンドウショッピングはごく軽く。しかしながら、実際はかなり重い。重くなった原因はむしろセキュリティ関連か?

Vine Linuxとのデュアルブート

Vine Linuxは7においてもUEFIには対応しないため、あくまでレガシーブートを使っていることが前提となる。

Vine Linuxでのデュアルブートのポイントは、

  • Disk Druidを用いて手動でパーティショニングを行う
  • /bootを別に切る(ほうが良い)
  • Grubは、sda(/bootのあるディスク)に対してインストール、高度なオプションを選択し、sda3に対してインストールする
  • ベースシステムのインストールでパッケージ基本構成を選択

MBR*レガシーブートの場合、Windows7は2つのパーティションを切っているはずだ。 sda1がブート関連、sda2がCドライブになる。

そこで、sda3をプライマリパーティションとして/bootに充て、sda4が拡張パーティション、sda5を/にする。 これ以上切る必要がなければsda5に全てを割り当ててもいいし、sda5をLVMにして、LVMタブで構成してもいい。

そして、/boot(sda3)に対してGrubをインストールする。 この方法が表面的に見えないが、「Grubの高度なオプション」として、次のステップで選択できるようになっている。

この状態でインストールを完了してもまだ起動できないため、SystemRescueCDで起動。

mount /dev/sda2 /mnt
dd if=/dev/sda3 of=/mnt/mbr.img bs=512 count=1	

そして再起動してWindows起動。

bcdedit /create /d "VineLinux" /application bootsector
bcdedit /set {<entry>} device partition=C:
bcdedit /set {<entry>} path \mbr.img
bcdedit /displayorder {<entry>} /addlast

<entry>は1つ目のコマンド実行時に表示される。

デフォルトで30秒あるから、という記事もみかけるが、これだと一瞬で決定されてしまい、操作できなかったので、

bcdedit /timeout 30

で30秒にする。

これでVineLinuxが起動できるようになる。で、Seed化とGUI化

おおよそ手順通りに、

export LANG=C
/etc/init.d/network start
apt-get update && apt-get upgrade
sed -i 's/6/VineSeed/g' /etc/apt/source.list.d/*
apt-get install apt-libxml2

Xのインストールよりも先に更新しておかないとコケる。

apt-get update && apt-get dist-upgrade
apt-get install task-xorg-x11 task-mate lightdm

これでまぁいけるのだが、いくつか追加

apt-get install fcitx-mozc task-kde

inittabの修正

cp -p /etc/inittab /etc/inittab.orig
cp -p /etc/inittab.sysv /etc/inittab
vim !!$

コピーしただけではランレベルは修正されていなかった。 なお、ベースシステムでインストールすると、ログイン時はキーボードがUSなのは仕様。

で、ここまでやったのだけれど、SeedのカーネルでもThinkPad e440のワイヤレスネットワークアダプタをサポートしていないので、結局断念…

bcdedit

これで目的のVine Linuxエントリを確認

bcdedit /delete {<entry>}

で削除できる。

コンピュータのプロパティからでもいけるよ、という話もあるようだ。

ところが

やっぱりDR-C125は認識されたりされなかったり。 というかほとんど認識されない。 ログオンしてもまっくらなままでログオンできないことが多い。 非常に不安定だ。フリーズや、Explorerの停止もよく出る。

Explorer停止に伴って再起動したところ、

Windowsの機能を構成する準備中

でパーセンテージ表示。 再起動すると

23799個のうちn個目の更新を適用中

という。

なんだこれは。

しかし、まるで普通に更新したかのように普通に立ち上がり、それ以降振る舞いは改善されたように見える。 これでWindowsが崩壊するようだと、なかなか困る。

悪いのはMicrosoftか。Lenovoか。

アメリカか。中国か。

Manjaro 0.8.13 LXQTを入れてみた

という理由でうまくいかなかったので、デスクトップと同じくArch派閥のManjaro Linux 0.8.13を入れてみた。

LXQTは古いコンピュータも活用できる軽量版で、軽量デスクトップ環境として人気のLXDEのQt portsだ。LXDEと同様の思想のQTデスクトップ環境を開発していたRazor-qtと合流し、LXDEはGtk+2バージョンをしばらくメンテナンスした後に、LXQtに統合されることになっている。

つまり、現在はGtk+2のLXDEと、Qt5のLXQtの2つがあるが、LXQtはLXDE Nextでもあり、徐々にLXDEは削除され、LXQtになるということだ。 LXQtがLXDEの後継である、ということでもある。

LXQtのコンポーネントは、多くがLXDEのPortsだが、LXTerminalをやめてQTerminalを採用している。

ちなみに、洪任諭氏がLXDEを離れてLXQtに移ったのに対して、LXDE開発チームは、むしろ活発にLXDEを開発し、洪任諭氏とは袂を分かち、LXDEを存続させる動きもみえる。 そのため、LXDEの存続が発表通りになるかはわからないし、LXDEユーザーがLXQtにうつるかもわからない。

LXQtは現在のところ、LXDEよりも、そしてXFceよりも重い。 XFceが意外とリソースを使うため、MATEよりも、そして場合によってはCinnamonよりも重いということになる。 もっとも、これは起動時に限ったことであり、必ずしも使っていて同様の体感が得られるわけではない。実際、XFceは結構軽い。

Manjaro 0.8.13 LXQtの導入については、手動ディスクパーティショニングを行うのだが、うまくいかなかった部分がある。

  • Thusインストーラは手動ディスクパーティショニングでLVMが使えない。
  • Swapパーティションを暗号化すると起動時にディスクを見つけられずエラーになる
  • 既存パーティションをフォーマットしようとすると失敗して書き込めなかったりおかしくなったりする。基本的にパーティションを消して作りなおす

既存パーティションに書けないというのは、前方に配置してしまうとインストールできないということになる。なかなか厄介。また、Swapパーティションが暗号化できないのもセキュリティ面では結構痛かったりする。 Windowsも暗号化されていない現状のため、看過するほかない。今までのところ完全なソリューションを提供したのはPCLinuxOSで、openSUSEも恐らくは問題ない。 openSUSEは安定した、完全なソリューションであることが多い。 ただし、openSUSE 13.2は不完全さが目立つと言われている。また、openSUSEはかなりパッケージは多いものの、割とstrictなOSSポリシーのため外部リポジトリに依存する部分が大きい。Factoryを使うのはかなり限定的な使用になり、望ましい環境さえ作れればArchほどの快適性はない。

どのようにするか、ということが決めかねるので現状このままとし、Windows10にするのであれば(EFSが使えるようになるので)Windows7は旧来の方式に戻して、Windows10にアップグレード、LinuxはopenSUSEを選択。 もしそこでUEFIへの変更が叶うのであれば、Manjaroでも問題ない。

とりあえず、バックアップの上でManjaro GrubをPBRへインストールすることを試みてみようと思う。

update-grubが何を対象にするかが心配なところ。

シェルでrcファイル更新時に既存シェルに再読み込みさせる

にゃおきゃっとさん(@nyaocat])がbashrcの更新に合わせて全bashに反映させたいというツイートをしていたので、

exec bashする方法を提案してみた。

で、結構うまくいくようなので、採用されたみたい。

この点について解説してみる。

exec(2)は現在のプロセスを置き換えるシステムコールで、execコマンドは引数コマンドを現在のプロセス実行し、実行中プロセスと置き換える。

これによって新規bashが起動される。この際

  • PIDは変わらない
  • プロセスの親子関係も変わらない
  • execされた場合、bashはジョブに対してSIGHUPを送らない(子プロセスが終了したりはしない)
  • ジョブテーブルは現行プロセスに固有の情報なので、引き継がれない。バックグラウンドジョブがあった場合、再読み込みされたシェルでjobsしてもリストされない
  • シェル起動後に覚えさせた変数、関数などは引き継がれない。環境変数も消滅する
  • 既に動いている子プロセスに対する影響は全く無い

子プロセスに影響がないのは、親プロセスの変更は子プロセスに伝播しないためだ。 環境変数の変更はあくまでそのプロセスと、そのプロセスから生成されるプロセスに対する影響である。プロセス生成時に引き継がれるだけだからだ。

それどころか、親プロセスが死んで孤児になると、initが引き継ぐが、それでも子プロセスには影響しない。

問題は、積極的にインタラクティブシェルで変数や関数やエイリアスを活用している人は、それらが全てリセットされてしまうことだろう。 あと、ジョブテーブルが消えるのも、ジョブを活用している人には痛い。

.zshrcなら以下で、SIGHUPを送った時に読みなおすようになる。

TRAPHUP() {
  exec zsh -l
}

連番ファイルの並べ替え、差し込み

彼女に書籍の電子化作業を頼んだのだが、あまりにも雑でかなり困った。

まず大量にあった、ページ順が逆になっているものについては、次のスクリプトをかいた

#!/usr/bin/zsh

files=(*)
dfiles=(${(aO)files})

print -l $dfiles

for i in "$files[@]"
do
  mv -v "$i" "$i.tmp"
done

integer index

for (( index = 1; index <= ${#files} ; index++ ))
do
mv -v "$files[$(( index ))].tmp" "$dfiles[ $(( index )) ]"
done

逆順はまだしも、差し込みはきつかった。 どこで何をしたかは説明したくないので、打ったコマンドをまとめて。 (Zsh)

for i in *
do
mv $i $i[6,8].jpg
done


for i in <100->*
do
mv $i $(( ${i:r} + 36 )).jpg
done

for i in <23-99>*
do
mv $i 0$(( ${i[2,3]:r} + 36 )).jpg
done

for i in *
do
mv $i $i[6,8].jpg                 
done

files=(*)

for i in ${(aO)files}
do
mv $i 0$(( ${i[2,3]:r} + 17 )).jpg
done

for i in *
do
mv $i $i[6,8].jpg                 
done

for i in <100->*
do
mv $i $(( ${i:r} + 4 )).jpg 
done

for i in <93-99>*    
do
mv $i 0$(( ${i[2,3]:r} + 4 )).jpg   
done

for i in 01??.*
do
mv $i $i[2,-1]
done

for i in *
do
mv $i 0$(( ${i[3]:r} + 90 )).jpg
done

重要なのは

  • 必ず後ろからやる
  • nnnなので、100をこえるものは先にやる
  • 0nnなものはArithmatic expansionの前にちゃんと0をつける

そして、紙がまとめて通ってしまったものはどうしようもないし、ページが何の順番でもないものは再スキャンしたほうが早いので、ゴミ箱から探して組み直し。 所要時間はだいたい4時間。

ほんっとに疲れた。

Tweets保存のためのMikutterプラグイン

とりあえずコード

# -*- coding: utf-8 -*-
require 'json'

Plugin.create(:save_timeline) do
  
  logdir = "#{ENV['HOME']}/.mikutter/plugin/save_timeline/log"

  on_update do | service, messages |
    File.open("#{logdir}/#{BOOT_TIME.strftime("%y%m%d%H%M%S")}.#{service.user || "default"}", "a") do |f| 
      messages.each do |msg|
        f.puts JSON.dump msg.instance_variable_get(:@value) rescue puts $!
      end
    end

end

#  on_direct_messages do |service, dms|
#  end

end

プラグインの書き方を調べながら書いた。 色々インスペクションしたので、そこに時間がかかった。内容的には難しくない。

messagesArrayなのだけれど、その各要素はmsg.inspectするとHashに見えるが、実際はMessageクラスのオブジェクトだった。 Messageクラスはその内容をそのまま出力するメソッドがないようなので、msg.instance_variable_get(:@value)の形でデータを取得している。 もちろん、@valueに値が格納されていることを確認するまでが一番手間だった(全体で言えば、Messageクラスであることになかなか気づかなかった部分に時間がかかった)。

JSONライブラリは出力に際して1行にまとめてくれるため、単純に行出力していけば、行単位でパースして処理できるログファイルができあがる。

このあと、flockに対応させた。

ダイレクトメッセージも対応したかったが、on_direct_messagesの取り扱いがよくわからなかったので、そのままにした。

追記

GitHubにてコードは公開中。

Mikutterのプラグインページにも掲載させていただいた。

BerryjackをTwitpic対応に

これはあくまで学術研究目的のレポートである。活用は自己責任にてお願いしたい。

まずはdiff

diff --git a/berryjack b/berryjack
index 378a970..c00e889 100755
--- a/berryjack
+++ b/berryjack
@@ -124,11 +124,12 @@ function get_media_url()
       fi
     done
     # image
-    for image in $( grep -Eo 'https://pbs\.twimg\.com/media/[a-zA-Z0-9_\-]+\.(jpg|png)' $tmp | sort | uniq | \
-      (if [ $orig -eq 0 ]; then
-        cat
+    for image in $( grep -Eo 'https://pbs\.twimg\.com/media/[a-zA-Z0-9_\-]+\.(jpg|png)|https?://twitpic.com/[a-z0-9]*' $tmp | sort | uniq | \
+      (
+      if [ $orig -eq 0 ]; then
+        sed 's#twitpic.com/\([0-9a-z]*\)#twitpic.com/show/full/\1#'
       else
-        sed 's/$/:orig/g'
+        sed 's#twitpic.com/\([0-9a-z]*\)#twitpic.com/show/full/\1#' | sed '/pbs\.twimg\.com/ s/$/:orig/g'
       fi
       ) )
     do
     

TwitpicのURIを拾うのは、単純にorでgrepがTwitpicのURIを拾ってくれるようにすれば良い。 だが、TwitpicのURIは画像のURIではなくページのURIなので、sedで画像のURIに変換している。 pbs.twimg.comのURIも対象にしているが、該当部分はおそらくないため、単純に無視される。 なお、URIはhttps?://twitpic.com/[a-z0-9]*に合致するもののみを想定している。

これで取得できる。 Crawlするためのシンプルなコード。保存するベースとなるディレクトリにおき、<userid>/.idというファイルを作成する。

#!/usr/bin/zsh

for idfile in */.id
do
  (
 	  print -- "-*- -*- -*- ${${idfile:h}:t} -*- -*- -*-"
   	cd "${idfile:h}"
   	berryjack "${${idfile:h}:t}"
  )
done

VDPAU / VAAPI * AMD A10 kaveri / Cinnamonが立ち上がらない

LinuxでのGPUハードウェアアクセラレーションつきでの再生のトライ。

設定はわかっているが動作のためにセットアップ。

VDPAUを利用するため、libvdpau-va-glとlibva-xvba-driverのインストールを行い、/etc/profile.d/vdpau_vaapi.sh

#!/bin/sh
export VDPAU_DRIVER=va_gl

と設定して実行可能に。(root:root 744)。再起動して有効化できる。 別パッケージのvdpauinfoによると

libva info: VA-API version 0.38.0
libva info: va_getDriverName() returns 0
libva info: Trying to open /usr/lib/dri/fglrx_drv_video.so
libva info: Found init function __vaDriverInit_0_33
libva info: va_openDriver() returns 0
display: :0.0   screen: 0
[VS] Software VDPAU backend library initialized
API version: 1
Information string: OpenGL/VAAPI/libswscale backend for VDPAU

Video surface:

name   width height types
-------------------------------------------
420     1920  1080  NV12 YV12 UYVY YUYV Y8U8V8A8 V8U8Y8A8 
422     1920  1080  NV12 YV12 UYVY YUYV Y8U8V8A8 V8U8Y8A8 
444     1920  1080  NV12 YV12 UYVY YUYV Y8U8V8A8 V8U8Y8A8 

Decoder capabilities:

name                        level macbs width height
----------------------------------------------------
MPEG1                          --- not supported ---
MPEG2_SIMPLE                   --- not supported ---
MPEG2_MAIN                     --- not supported ---
H264_BASELINE                  51 16384  2048  2048
H264_MAIN                      51 16384  2048  2048
H264_HIGH                      51 16384  2048  2048
VC1_SIMPLE                     --- not supported ---
VC1_MAIN                       --- not supported ---
VC1_ADVANCED                   --- not supported ---
MPEG4_PART2_SP                 --- not supported ---
MPEG4_PART2_ASP                --- not supported ---
DIVX4_QMOBILE                  --- not supported ---
DIVX4_MOBILE                   --- not supported ---
DIVX4_HOME_THEATER             --- not supported ---
DIVX4_HD_1080P                 --- not supported ---
DIVX5_QMOBILE                  --- not supported ---
DIVX5_MOBILE                   --- not supported ---
DIVX5_HOME_THEATER             --- not supported ---
DIVX5_HD_1080P                 --- not supported ---
H264_CONSTRAINED_BASELINE      --- not supported ---
H264_EXTENDED                  --- not supported ---
H264_PROGRESSIVE_HIGH          --- not supported ---
H264_CONSTRAINED_HIGH          --- not supported ---
H264_HIGH_444_PREDICTIVE       --- not supported ---
HEVC_MAIN                      --- not supported ---
HEVC_MAIN_10                   --- not supported ---
HEVC_MAIN_STILL                --- not supported ---
HEVC_MAIN_12                   --- not supported ---
HEVC_MAIN_444                  --- not supported ---

Output surface:

name              width height nat types
----------------------------------------------------
B8G8R8A8         457866064 457866064    y  
R8G8B8A8         457866064 457866064    y  
R10G10B10A2      457866064 457866064    y  
B10G10R10A2      457866064 457866064    y  
A8               457866064 457866064    y  

Bitmap surface:

name              width height
------------------------------
B8G8R8A8         16384 16384
R8G8B8A8         16384 16384
R10G10B10A2      16384 16384
B10G10R10A2      16384 16384
A8               16384 16384

Video mixer:

feature name                    sup
------------------------------------
DEINTERLACE_TEMPORAL             -
DEINTERLACE_TEMPORAL_SPATIAL     -
INVERSE_TELECINE                 -
NOISE_REDUCTION                  -
SHARPNESS                        -
LUMA_KEY                         -
HIGH QUALITY SCALING - L1        -
HIGH QUALITY SCALING - L2        -
HIGH QUALITY SCALING - L3        -
HIGH QUALITY SCALING - L4        -
HIGH QUALITY SCALING - L5        -
HIGH QUALITY SCALING - L6        -
HIGH QUALITY SCALING - L7        -
HIGH QUALITY SCALING - L8        -
HIGH QUALITY SCALING - L9        -

parameter name                  sup      min      max
-----------------------------------------------------
VIDEO_SURFACE_WIDTH              -  
VIDEO_SURFACE_HEIGHT             -  
CHROMA_TYPE                      -  
LAYERS                           -  

attribute name                  sup      min      max
-----------------------------------------------------
BACKGROUND_COLOR                 -  
CSC_MATRIX                       -  
NOISE_REDUCTION_LEVEL            -  
SHARPNESS_LEVEL                  -  
LUMA_KEY_MIN_LUMA                -  
LUMA_KEY_MAX_LUMA                -  

H.264しかサポートできていない?

VAAPIはAMD APU A10 Kaveriで必要なのはlibva-xvba-driverなので、それだけでOK。Catalystドライバは既に使用している。 Mplayerはmplayer-vaapiをAURから導入すれば良いということだが(コマンドラインオプションは必要。Wikiは英語版mplayerの項目でのみ、AURにあることが示されている。communityからdropしたパッケージ)、現在のところ鍵が検証できない(手動追加しても受け付けない)ので試していない。 SMplayerはVAAPIはIntelのみだと言ってくる。

結局うまく動いていない気がする。

Cinnamonが立ち上がらない

再起動すると、Cinnamonが立ち上がらなくなった。

待たされた上でデフォルトの壁紙が表示され、

Cinnamonはクラッシュしました

と表示される。

~/xsession-errorsを調べると、~/.config/dconfがPermission Deniedになっている。

ls -ldR ~/.config/dconf

したところ、ごっそりとパーミッションがroot:rootのmask077になっている。 chownしたのだが、chownしても何度も戻ってしまい、ちょっと苦労した。

PureBuilder2 (2)

Kramdown拡張でPDocオブジェクト化

PureBuilder2はもともと思っていたよりもかなり大規模なものになっているが、MarkdownオブジェクトをPureDocと同様に扱えるようにする、というのが今回のテーマ。

例えばテンプレートで

DOC.body

のように書かれている場合がある。この場合は当然、HTMLへ変換したのであればHTML文字列が得られなくてはいけない。 また、

DOC.meta["title"]

のようにもアクセスできる。 それだけなら単にアクセッサを拡張してやればいい話なのだが、PureDocオブジェクトはTOCのためのループ機能が組み込まれている。 これにより章立てをループさせることができ、簡単に任意の形式でTOCを組める。 これはどうしてもパース時に情報を取らなくてはいけない。

もし、HTMLに出力するものである、というのであれば、単純に結果のHTMLをパースして取得する方法もある。 だが、KramdownライブラリはLaTeXとPDFをサポートする。PureDocもゆくゆくはLaTeX形式での出力をサポートする予定である。

であれば、やはりKramdownでのMarkdownパース時にTOCを作りたい。

基本的な方針としては、実際にPureDocオブジェクトを使用する。 これはパーサ/コンバータを含まないベースクラスで、本来は直接このクラスのインスタンスを生成することは想定していなかった。 だが、外側から使用するメソッドは一通り持っており、インターフェイスは揃っている。

DOC.bodyで返すべき@bodyDOC.body=を用いて入れ、DOC.metaに関してはPureDocクラスが持っている機能によってドキュメントから取り込むといったことが可能。 そのため、DOCPureDocインスタンスであり、Kramdownの結果はDOC.body=によって入れるだけだ。

だが、DOC.stock_ehaderを用いてヘッダを入力し、TOCを生成できるようにしなければいけない。 そこで、Kramdownに手を入れる必要があった。

ソースコードを追っていったが、結局Kramdown::Parser::Kramdown#new_block_elをオーバーライドするのが良いと分かった。 ヘッダを取得するパートはあるが、new_block_elメソッドはメソッド自体が短く、あくまでパース時に各エレメント対して呼ばれるものだ。何のために呼ばれているかを判定する必要もなく、引数を丸々渡すだけで良いため、overrideしやすかった。

require 'kramdown'

# Override Kramdown
class Kramdown::Parser::Kramdown

  alias _new_block_el_orig new_block_el
  

def new_block_el(*arg)

   	if arg[-1].kind_of?(Hash)
    
      case arg[0]
      
      # Is Header?
      when :header
        p arg[-1][:level]
        p arg[-1][:raw_text]
      end
      
    end
    
    _new_block_el_orig(*arg)

end end

p Kramdown::Document.new(ARGF.read).to_html

というテストコードを書き、実際に動作することを確認、when :header部分を

::DOC.stock_header(arg[-1][:level], arg[-1][:raw_text])

と書き換えた。

KramdownはPure Rubyで書かれているため、扱いやすいし、ソースコードを書くのも楽だ。 だが、できればサブクラス化するなど、もう少しスマートな方法でできればよかったな、と思う。クラスが細かく分割されて連携しているため、置き換えるのはかなり難しいと判断した。

Kramdownは非常に良いライブラリなのは間違いない。

forkの代わりに

RubyのKernel.forkをはじめとするfork機能(例えば、IO.popen-を渡すことを含む)はWindowsでは動作しない。 Perlerだった私としてはこれはかなり不満な点だ。Perlはコミュニティの努力により、forkがWindows上で動作する。これは、Windows版Perlではforkをエミュレートするためだ。

今回は、設定やドキュメントオブジェクトなどをセットアップした状態で、forkによって環境を独立させたいと考えていた。 これはグローバルなオブジェクトに変更を加えるためであり、また出力先の制御をSTDOUT.reopenによって行うことができるかということについて考えていたためだ。

RubyのforkとWindowsについて検索すると、「forkは邪悪だ、threadを使え」という内容があふれる。 だが、今回は並列化のために使いたいわけではないため、Threadは用を成さない。

また、大量のドキュメントを変換する際のオーバーヘッド低減という目的もある。

Unicorn(Webアプリケーションサーバー)がこのforkによるCOWを活用した設計となっている。Unicornはどうしているのかと調べてみたら、UnicornもMongrelもWindowsでは動作しないらしい。

というわけで、forkの利用は諦めて、グローバルな名前に対する変更をいなす方向とした。

グローバルな名前のオブジェクトが変更されるのは、ほとんど

DOC.is {
...
}

という書式で記述するためだ。 これはPureDocドキュメントを分かりやすく記述するためであり、実際にテンプレートもDOCオブジェクトを利用したデザインとなっている。 つまり、DOCはthe PureDoc objectであることを期待している。

この設計を維持するため、Delegateライブラリを使用することとした。 実体はDOCではなく、DOCはただのDelegatorというデザインだ。これはDOCに実体はなく、ただの代名詞となるわけだ。

DOC = SimpleDelegator.new(nil)

とすることにより、まずDOCという名前を用意しておく。 実際に新しいドキュメントを生成する場合は、

::DOC.__setobj__ @@config[:puredoc_class].new

のようにする。 これにより、DOCが意味するドキュメントを入れ替えることができ、DOCを変更しても、変更されるのはDOCではなく、移譲されているドキュメントであり、DOCをまた新しいドキュメントにすることもできる。