- 投稿日:2019-03-02T23:54:42+09:00
LSB(linux standard base) check
Linux Standard Base (LSB) とはなにか (2)
https://bitwalk.blogspot.com/search/label/LSBに書かれている事項をdockerで
$ docker run -it ubuntu /bin/bash# apt update # apt install -y sudo apt-utils vim wget # wget lsb-app-checker-local-5.0.0-3.x86_64.tar.gz # tar xvf lsb-app-checker-local-5.0.0-3.x86_64.tar.gz# ./install.sh This system appears to be a variant of Debian GNU/Linux, such as Debian itself, Ubuntu, MEPIS, Xandros, Linspire, etc. However, the alien package (which is necessary to install LSB packages on Debian-based systems) is not currently installed. This is likely a more serious problem, in that alien is required for your system to be LSB-compliant. You should install the "lsb" package, and try running this script again.apt install usb# ./install.sh This system appears to be a variant of Debian GNU/Linux, such as Debian itself, Ubuntu, MEPIS, Xandros, Linspire, etc. Is this correct? y Installing packages... There may have been problems with the package installation. Check error-log.txt for more information. # cat error-log.txt warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY warning: lsb-app-checker-5.0.0.0-1.i486.rpm: Header V4 RSA/SHA1 Signature, key ID 178f06d7: NOKEY lsb-app-checker-5.0.0.0-1.i486.rpm is for architecture i386 ; the package cannot be built on this system文書履歴(document history)
ver. 0.01 初稿 20190302
- 投稿日:2019-03-02T23:30:42+09:00
Go初心者が書くLinux展開/解凍コマンド
はじめに
僕はUbuntuユーザなのですが,Linuxを使っているといろんな種類の圧縮ファイルと遭遇します.
例えば
-.gz
-.zip
-.tar
-.tar.gz / .tar.bz2
などがあります.基本的にファイラからファイルをダブルクリックしたら展開/解凍できるのですが,コマンドで展開したい場面も多くあります.しかしながら,圧縮タイプによってコマンドが異なるため,それぞれ展開コマンドを覚える /「tar.gz 解凍 コマンド」などとググる必要があり,空間/時間計算量が増加してしまいます.
コマンド1つで展開できたら便利じゃね?となるのは自然なことで,Golangの勉強がてらそんなコマンドを書いてみました.注意
- 勉強し始めて一日で書いたもので,僕はGoに関しては無知です.(
Goroutine
)
- 多分,5,6時間で書いたものです.
- このコマンドはまだ完成していません.
- Goの導入に関しては
sudo apt install golang
で何を作ったの?
goaunpack
(名前については後述) というコマンドを作りました.
コマンド一つで複数の(異なるタイプの)圧縮ファイル/ディレクトリを展開します.
また,.zip, .tar.gz
などのアーカイブファイルを展開するときのあるあるなのですが,複数ファイルをディレクトリに入れずに圧縮する場合,展開時にカレントディレクトリにファイルが散らばることがあります.goaunpack
では,ディレクトリを自動作成してこれを防ぎます.Goroutineをつかって並列処理でファイル展開を行います(多分).
使用例
-goaunpack archive.zip
: .圧縮ファイルの展開
-goaunpack *.tar.gz
: 複数の圧縮ファイルの展開
-goaunpack *
: 複数の異なるタイプの圧縮ファイルの展開
-goaunpack file
: 拡張子のない圧縮ファイルの展開僕,無知なの? → はいそうです
atool
はい,そんな便利コマンドはもうあります.書いている途中で知りました.これで,代替できます.sudo apt install atool
でインストールできます.goaunpack
の名前はatool
のコマンドをもじったものです.
goaunpack
では並列処理でファイルを展開できます. → atoolでできるかは不明.
- 展開
aunpack
- 圧縮
apack
- 圧縮ファイル内のファイル表示
als
archiver
よくわからんけどなんかGoで書かれたやつ.
goaunpack
は外部コマンドを使っていますが,これはGoだけで書かれているみたいですね.
もちろん書いている途中で知りました,こっちのほうが便利でしょう.しらんけど.Go コード
goaunpack.gopackage main import ( "fmt" "flag" "sync" "strings" "os" "os/exec" ) // Global variables var ( SupportedExtensions = []string{ "zip", "tar", "gz", "bz2", "7z", "tgz", "tbz", "tar.gz", "tar.bz2"} Verbose = false TargetDir = "" ) func main(){ verbose := flag.Bool("v", false, "print messages") targetDir := flag.String("d", "./", "output directory") numWorkers := flag.Int("w", 10, "maximum # of parallel") // flag.TYPE(option name, default value, help message) flag.Parse() args := flag.Args() Verbose = *verbose TargetDir = *targetDir // unpack files with ?Goroutine? ch := make(chan string) wg := sync.WaitGroup{} // make workers for i:=0; i<*numWorkers; i++{ wg.Add(1) go callUnpacker(&wg, ch) } // channel ni fileName wo nagasu for _, fileName := range args { ch <- fileName } close(ch) wg.Wait() } // util functions func getExtension(fileName string) (string) { var extension string s := strings.Split(fileName, ".") extension = s[len(s)-1] // check tar.xx if len(s) > 1 { if s[len(s)-2] == "tar"{ extension = "tar" } } // check an extension is supported or not isSupported := false for _, supExt := range SupportedExtensions { if extension == supExt { isSupported = true break } } // identify non-supported extension using file command if !isSupported { outCheck, _ := exec.Command("file", "-z", fileName).Output() strOutCheck := string(outCheck) // check extension if strings.Contains(strOutCheck, "bzip2 compressed data"){ extension = "bz2" } else if strings.Contains(strOutCheck, "gzip compressed data") { extension = "gz" } else if strings.Contains(strOutCheck, "Zip archive data") { extension = "zip" } else if strings.Contains(strOutCheck, "tar archive") { extension = "tar" } else { extension = "unknown" } } return extension } func getTargetDir(fileName string, topChar []string) (string) { hasCommonTop := true top0 := topChar[0] for _, topN := range topChar { if top0 != topN { hasCommonTop = false break } } var targetDir string if hasCommonTop { targetDir = TargetDir } else { s1 := strings.Split(fileName, "/") s2 := strings.Split(s1[len(s1)-1], ".") header := s2[0] // moshi TargetDir no matsubi ga / denai nara / wo // tuketasu endStr := string(TargetDir[len(TargetDir)-1]) if endStr == "/"{ targetDir = TargetDir + header } else { targetDir = TargetDir + "/" + header } if _, err := os.Stat(targetDir); os.IsNotExist(err) { os.Mkdir(targetDir, 0777) } } return targetDir } // unpacker func callUnpacker(wg *sync.WaitGroup, ch chan string){ defer wg.Done() // genri ha humei for { fileName, isOpen := <- ch if !isOpen { return } extension := getExtension(fileName) switch extension { case "zip": unpackZip(fileName) case "tar": unpackTar(fileName) case "gz": unpackGz(fileName) case "bz2": unpackBz2(fileName) case "7z": unpack7z(fileName) default: if Verbose { fmt.Println("non-supported extension:", extension) } } } } // these functions may be replace with templete func unpackZip(fileName string){ // check the tar file's structure outLook, _ := exec.Command("unzip", "-l", fileName).Output() strOutLook := strings.Split(string(outLook), "\n") // check the files has common top directory var topChar []string for _, line := range strOutLook[3:len(strOutLook)-3] { block := strings.Split(line, " ") if len(block) > 1 { top := strings.Split(block[len(block)-1], "/") topChar = append(topChar, top[0]) } } outExtract, _ := exec.Command("unzip", "-d", getTargetDir(fileName, topChar), fileName).Output() if Verbose { fmt.Println(string(outExtract)) } } func unpackTar(fileName string){ // check the tar file's structure outLook, _ := exec.Command("tar", "-tvf", fileName).Output() strOutLook := strings.Split(string(outLook), "\n") // check the files has common top directory var topChar []string for _, line := range strOutLook { block := strings.Split(line, " ") if len(block) > 1 { top := strings.Split(block[len(block)-1], "/") topChar = append(topChar, top[0]) } } outExtract, _ := exec.Command("tar", "-xvf", fileName, "-C", getTargetDir(fileName, topChar)).Output() if Verbose { fmt.Println(string(outExtract)) } } func unpackGz(fileName string){ fmt.Println("This is gz file: ", fileName) out, _ := exec.Command("gzip", "-d", fileName).Output() if Verbose { fmt.Println(out) } } func unpack7z(fileName string){ fmt.Println("7z has not be supported yet", fileName) } func unpackBz2(fileName string){ // fmt.Println("This is bz2 file: ", fileName) out, _ := exec.Command("bzip2", "-d", fileName).Output() if Verbose { fmt.Println(out) } }インストール
go build goaunpack.go mv goaunpack /パスの通ったディレクトリ
必要な外部コマンド
sudo apt install file unzip tar gzip bzip2おわりに
Goの勉強で書いてみました.いつもはPython3を書いているのですが,Goも書きやすい言語ですね(Pythonほどではない).ただ,使っていない変数やモジュールがあるだけでコンパイルエラーになるのはめんどくさいですね.
興味を持っていただけたり,改善点があればコメントしていただけると嬉しいです.
- 投稿日:2019-03-02T23:30:42+09:00
Go初心者が書くLinux用 圧縮ファイルの展開/解凍コマンド
はじめに
僕はUbuntuユーザなのですが,Linuxを使っているといろんな種類の圧縮ファイルと遭遇します.
例えば
-.gz
-.zip
-.tar
-.tar.gz / .tar.bz2
などがあります.基本的にファイラからファイルをダブルクリックしたら展開/解凍できるのですが,コマンドで展開したい場面も多くあります.しかしながら,圧縮タイプによってコマンドが異なるため,それぞれ展開コマンドを覚える /「tar.gz 解凍 コマンド」などとググる必要があり,空間/時間計算量が増加してしまいます.
コマンド1つで展開できたら便利じゃね?となるのは自然なことで,Golangの勉強がてらそんなコマンドを書いてみました.注意
- 勉強し始めて一日で書いたもので,僕はGoに関しては無知です.(
Goroutine
)
- このコマンドはまだ完成していません.
- Goの導入に関しては
sudo apt install golang
で何を作ったの?
goaunpack
(名前については後述) というコマンドを作りました.
コマンド一つで複数の(異なるタイプの)圧縮ファイル/ディレクトリを展開します.
また,.zip, .tar.gz
などのアーカイブファイルを展開するときのあるあるなのですが,複数ファイルをディレクトリに入れずに圧縮する場合,展開時にカレントディレクトリにファイルが散らばることがあります.goaunpack
では,ディレクトリを自動作成してこれを防ぎます.Goroutineをつかって並列処理でファイル展開を行います(多分).
使用例
-goaunpack archive.zip
: .圧縮ファイルの展開
-goaunpack *.tar.gz
: 複数の圧縮ファイルの展開
-goaunpack *
: 複数の異なるタイプの圧縮ファイルの展開
-goaunpack file
: 拡張子のない圧縮ファイルの展開僕,無知なの? → はいそうです
atool
はい,そんな便利コマンドはもうあります.書いている途中で知りました.これで,代替できます.sudo apt install atool
でインストールできます.goaunpack
の名前はatool
のコマンドをもじったものです.
goaunpack
では並列処理でファイルを展開できます. → atoolでできるかは不明.
- 展開
aunpack
- 圧縮
apack
- 圧縮ファイル内のファイル表示
als
archiver
よくわからんけどなんかGoで書かれたやつ.
goaunpack
は外部コマンドを使っていますが,これはGoだけで書かれているみたいですね.
もちろん書いている途中で知りました,こっちのほうが便利でしょう.しらんけど.Go コード
goaunpack.gopackage main import ( "fmt" "flag" "sync" "strings" "os" "os/exec" ) // Global variables var ( SupportedExtensions = []string{ "zip", "tar", "gz", "bz2", "7z", "tgz", "tbz", "tar.gz", "tar.bz2"} Verbose = false TargetDir = "" ) func main(){ verbose := flag.Bool("v", false, "print messages") targetDir := flag.String("d", "./", "output directory") numWorkers := flag.Int("w", 10, "maximum # of parallel") // flag.TYPE(option name, default value, help message) flag.Parse() args := flag.Args() Verbose = *verbose TargetDir = *targetDir // unpack files with ?Goroutine? ch := make(chan string) wg := sync.WaitGroup{} // make workers for i:=0; i<*numWorkers; i++{ wg.Add(1) go callUnpacker(&wg, ch) } // channel ni fileName wo nagasu for _, fileName := range args { ch <- fileName } close(ch) wg.Wait() } // util functions func getExtension(fileName string) (string) { var extension string s := strings.Split(fileName, ".") extension = s[len(s)-1] // check tar.xx if len(s) > 1 { if s[len(s)-2] == "tar"{ extension = "tar" } } // check an extension is supported or not isSupported := false for _, supExt := range SupportedExtensions { if extension == supExt { isSupported = true break } } // identify non-supported extension using file command if !isSupported { outCheck, _ := exec.Command("file", "-z", fileName).Output() strOutCheck := string(outCheck) // check extension if strings.Contains(strOutCheck, "bzip2 compressed data"){ extension = "bz2" } else if strings.Contains(strOutCheck, "gzip compressed data") { extension = "gz" } else if strings.Contains(strOutCheck, "Zip archive data") { extension = "zip" } else if strings.Contains(strOutCheck, "tar archive") { extension = "tar" } else { extension = "unknown" } } return extension } func getTargetDir(fileName string, topChar []string) (string) { hasCommonTop := true top0 := topChar[0] for _, topN := range topChar { if top0 != topN { hasCommonTop = false break } } var targetDir string if hasCommonTop { targetDir = TargetDir } else { s1 := strings.Split(fileName, "/") s2 := strings.Split(s1[len(s1)-1], ".") header := s2[0] // moshi TargetDir no matsubi ga / denai nara / wo // tuketasu endStr := string(TargetDir[len(TargetDir)-1]) if endStr == "/"{ targetDir = TargetDir + header } else { targetDir = TargetDir + "/" + header } if _, err := os.Stat(targetDir); os.IsNotExist(err) { os.Mkdir(targetDir, 0777) } } return targetDir } // unpacker func callUnpacker(wg *sync.WaitGroup, ch chan string){ defer wg.Done() // genri ha humei for { fileName, isOpen := <- ch if !isOpen { return } extension := getExtension(fileName) switch extension { case "zip": unpackZip(fileName) case "tar": unpackTar(fileName) case "gz": unpackGz(fileName) case "bz2": unpackBz2(fileName) case "7z": unpack7z(fileName) default: if Verbose { fmt.Println("non-supported extension:", extension) } } } } // these functions may be replace with templete func unpackZip(fileName string){ // check the tar file's structure outLook, _ := exec.Command("unzip", "-l", fileName).Output() strOutLook := strings.Split(string(outLook), "\n") // check the files has common top directory var topChar []string for _, line := range strOutLook[3:len(strOutLook)-3] { block := strings.Split(line, " ") if len(block) > 1 { top := strings.Split(block[len(block)-1], "/") topChar = append(topChar, top[0]) } } outExtract, _ := exec.Command("unzip", "-d", getTargetDir(fileName, topChar), fileName).Output() if Verbose { fmt.Println(string(outExtract)) } } func unpackTar(fileName string){ // check the tar file's structure outLook, _ := exec.Command("tar", "-tvf", fileName).Output() strOutLook := strings.Split(string(outLook), "\n") // check the files has common top directory var topChar []string for _, line := range strOutLook { block := strings.Split(line, " ") if len(block) > 1 { top := strings.Split(block[len(block)-1], "/") topChar = append(topChar, top[0]) } } outExtract, _ := exec.Command("tar", "-xvf", fileName, "-C", getTargetDir(fileName, topChar)).Output() if Verbose { fmt.Println(string(outExtract)) } } func unpackGz(fileName string){ fmt.Println("This is gz file: ", fileName) out, _ := exec.Command("gzip", "-d", fileName).Output() if Verbose { fmt.Println(out) } } func unpack7z(fileName string){ fmt.Println("7z has not be supported yet", fileName) } func unpackBz2(fileName string){ // fmt.Println("This is bz2 file: ", fileName) out, _ := exec.Command("bzip2", "-d", fileName).Output() if Verbose { fmt.Println(out) } }インストール
go build goaunpack.go mv goaunpack /パスの通ったディレクトリ
必要な外部コマンド
sudo apt install file unzip tar gzip bzip2おわりに
Goの勉強で書いてみました.いつもはPython3を書いているのですが,Goも書きやすい言語ですね(Pythonほどではない).ただ,使っていない変数やモジュールがあるだけでコンパイルエラーになるのはめんどくさいですね.
興味を持っていただけたり,改善点があればコメントしていただけると嬉しいです.
- 投稿日:2019-03-02T23:14:48+09:00
kvmでubuntu インストール中Loading libc6-udeb failed for unknown reasons. Abortingが出たとき
ubuntu18とか14だと動く(えっ)
- 投稿日:2019-03-02T22:40:51+09:00
鍵認証によるSSH接続を設定する
1.仕組み
「ssh 鍵認証 仕組み」でぐぐれば世の中の先人たちがわかりやすく解説しているので
ポイントだけまとめると以下のような感じ.
- (クライアント)秘密鍵と公開鍵のセットを生成
- (接続先サーバ)公開鍵を登録
- (接続先サーバ)クライアントからの接続を受け付け,公開鍵を用いて乱数を暗号化
- (接続先サーバ)乱数をハッシュ化
- (クライアント)受け取った乱数をハッシュ化し,ハッシュ値をサーバへ転送
- (接続先サーバ)クライアントが送信してきたハッシュ値とサーバ側で生成したハッシュ値を比較
2.設定してみる
2-1.鍵セットの生成
# -t:暗号方式の指定 -f:ファイル名の指定 ssh-keygen -t rsa -f test_rsa2-2.公開鍵の登録
# サーバにて作業,接続するユーザを対象に実施すること cat test_rsa.pub >> .ssh/authorized_keys2-3.鍵認証の有効化
# vim /etc/ssh/sshd_config RSAAuthentication yes PubkeyAuthentication yes AuthorizedKeyFile .ssh/authorized_keys # 強固にしたければ,パスワード認証の無効化 PasswordAuthentication no3.接続してみる
ファイル名を指定している場合,秘密鍵を指定する必要がある.
# -i:秘密鍵の指定 ssh -i .ssh/test_rsa -p12345 hoge@hogehoge.hoge
- 投稿日:2019-03-02T20:50:50+09:00
タイムスタンプつきバックアップファイルを作成するコマンド
サーバーの設定ファイルとかをいじるときによく使うので忘れないようにメモ
$ cp -p ファイル名{,.`date "+%Y%m%d%H"`}実行結果
$ cp -p hoge{,.`date "+%Y%m%d%H"`} $ ls hoge hoge.2019030220補足
バックアップファイルから戻し作業をする場合は以下のような感じ
mv hoge{.`date "+%Y%m%d%H"`,}ちなみに、戻し用にバックアップファイルを作成する場合は『時』くらいの粒度のタイムスタンプにしたほうがいいと思います。
というのも、秒単位のタイムスタンプにすると、戻し作業をする際にファイルを見つけることができないからです。
mv hoge{.`date "+%Y%m%d_%H%M%S"`,} mv: hoge.20190302_204733: No such file or directoryさいごに
詳細をブログに書きました。ぜひご覧になってください↓
タイムスタンプのついたバックアップファイルを簡潔に作成する方法ツイッター(@nishina555)やってます。フォローしてもらえるとうれしいです!
- 投稿日:2019-03-02T19:25:11+09:00
Linuxの時間変数(jiffies)でハマったこと
Linuxには色々な時間変数がありますが、このjiffiesにハメられたので記録しておきます。(勝手にハマっただけ)
変数jiffies
Kernel起動時からtick(タイマー割込み)を数えた回数。
#define HZ
のCONFIG_HZの値で計算される。
仕事の環境では、HZ=200
だった。jiffiesは
HZ
の間隔でカウントアップされていく値である。
つまり、jiffiesの値をHZ
で割れば、secが算出されるハズである。32bit環境
例jiffies = 348,264 \\ HZ = 200\\ とした場合、\\ \begin{align} jiffies\ / HZ &= 348,264\ /\ 200 \\ &= 1,741.3\ [sec] \\ &= 29.8\ [min] \end{align}この計算は、公式APIの
unsigned int jiffies_to_msecs(const unsinged long j)
でも同じ計算をしている。
計算式自体は決して間違っていない。しかし、64bit環境では思ったように答えが出ないのである。
64bit環境
例jiffies = 4,295,130,087 \\ HZ = 200\\ とした場合、\\ \begin{align} jiffies\ / HZ &= 4,795,130,087\ /\ 200 \\ &= 2,395,650.435\ [sec] \\ &= 39,927.50725\ [min] \end{align}は?20分ぐらいしか待ってないのに何それ?
jiffiesの初期値
このjiffies、初期値がクッソ特徴的である。
- 32bit環境 初期値-5分
- 64bit環境 32bitの初期値に、上位32bitを0埋め
-5分が初期値って?\begin{align} jiffies &= -5\ _{(10)}\ [min] \\ &= -6,000\ _{(10)}\ [sec] \\ &= FFFF\ E890\ _{(16)} \\ \end{align}\\ ただし、64bit環境では上位32bitを0埋めするため、\\ 0000\ 0000\ FFFF\ E890\ _{(16)}
- 32bit環境の場合
FFFF E890
32bitの領域はこれでお終い。0000 0000
は32bit領域外。- 64bit環境の場合
0000 0000 FFFF E890
64bit幅なので、上位32bit(0000 0000
)は0だが領域として存在している。jiffiesは符号なし
こいつ、負数を初期値に取るクセしてunsigned型なのだ。
つまり、さっきの-5分はどんどんタイマーカウントを進めていって、5分後に綺麗に0000 0000 0000 0000
(16)になる。メモリ幅による値の変化
5分後、jiffiesの値が綺麗に0になるのはいい。
だが、コンピューターにおける加算して0になるには注意が必要だ。32bit幅の場合
結局、
(0000 0000) FFFF E890
の羅列はtick毎に加算されて行って0になる。
その瞬間は(0000 0001) 0000 0000
となる。
だが、上位32bit(0000 0001
の部分)は32bit領域外なので消えてしまう。その結果、32bitでは
0000 0000
だけが残り、真に0となってしまう。64bit幅の場合
0000 0000 FFFF E890
は加算され続けることで0になろうとするが、そうは問屋が卸さない。
0000 0001 0000 0000
となり、32bit幅では消えてしまった上位32bitの1が残り続ける。
つまり、
0000 0001 0000 0000
(16) =4294967296
(10)
0とはならないのである。64bit環境では、この値を引いてやらないと正しく計算できないわけだ。
再度、計算し直してみる。
jiffies = 4295130087\\ 4294967296 < jiffiesを満たすため、補正処理を導入する。\\ jiffies - 4294967296 = 162791\\ \begin{align}\\ jiffies / HZ &= 162791 / 200\\ &=813.955\ [sec]\\ &=13.6\ [min]\\ \end{align}\\ さらに、開始が-5分であるため\\ 18.6[min]体感で20分ぐらい経ってから取得した値なので、それなりに合ってそう。
結論
みんな大好き、オーバーフローには気をつけようね!!(雑)
- 投稿日:2019-03-02T15:46:52+09:00
VirtualBox + CentOS7でGUIが操作できなくなる問題の解決
はじめに
ホストOSにWindows10。VirtualBox 6.0にCentOS7を入れ使っているのですが、どうもバグがあるようですぐにGUIが反応しなくなります。
解決
以下の記事に書いてありました。
https://bugs.centos.org/view.php?id=15570カーネル 3.10.0-957.x.el7 特有の問題だそうです。
自分の使っているCentOS7は、、$ uname -a Linux localhost.localdomain 3.10.0-957.5.1.el7.x86_64 #1 SMP Fri Feb 1 14:54:57 UTC 2019 x86_64 x86_64 x86_64 GNU/Linuxビンゴ。
ではカーネルをココを参考にアップデートします。$ su # rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org # rpm -Uvh https://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm # yum --enablerepo=elrepo-kernel install kernel-ml # reboot起動するとkernelが3.10→4.20になっています。
しばらく使いましたが、確かに直ったようです。
【参考】kernel versionについて
Linuxのバージョンが3.10から4.20と大きくジャンプしています。。
私がLinuxを開発で使っていたのは2.6.16くらいの昔なのですが、今はだいぶバージョンの考え方が変わったようですね。https://elinux.org/images/8/86/Jamboree_62_LTS_20170901.pdf
Linux 3系から4系に変わるのも、大きな変更があったからではないそうです。
https://japan.zdnet.com/article/35060811/あと、ターミネータのT-800のkernelがLinuxで、4.1.15 というのは知りませんでした。。
- 投稿日:2019-03-02T15:26:31+09:00
LinuxマシンのサービスをDockerに移行するスクリプトを書いた
実行中のLinuxマシンからDockerのベースイメージを生成するスクリプトを書いてみました。
https://github.com/hidakanoko/vm2container
このスクリプトは指定されたパッケージの依存性を解決して、パッケージに含まれるコマンドを実行する(プロセスを起動する)のに必要なファイルを集めてDockerのベースイメージを作ります。
RPMを使ったシステムなら動くはずですが、今のところCentOS7でしかテストしていません...
実用性は低いような気がしますが、古いマシンをDockerに乗せ換えてとりあえず延命したいようなケースでは役に立つかも?
使い方
スクリプトのダウンロード
# git clone https://github.com/hidakanoko/vm2container.git Cloning into 'vm2container'... remote: Enumerating objects: 131, done. remote: Counting objects: 100% (131/131), done. remote: Compressing objects: 100% (79/79), done. remote: Total 131 (delta 68), reused 99 (delta 44), pack-reused 0 Receiving objects: 100% (131/131), 34.22 KiB | 0 bytes/s, done. Resolving deltas: 100% (68/68), done.Helpの表示
# cd vm2container/ # bin/v2c -h usage: vm2container [-h] [-p PACKAGE] [-s] [-l] [-a] [-d DIRECTORY] [-v VERBOSE] Create docker image from running full Linux environment. optional arguments: -h, --help show this help message and exit -p PACKAGE, --package PACKAGE -s, --showDeps -l, --listFiles -a, --createArchive -d DIRECTORY, --directory DIRECTORY -v VERBOSE, --verbose VERBOSE ERROR, WARN, INFO, DEBUGパッケージの依存関係をツリー表示する
-p <PACKAGE>
で起動したいコマンドを含むパッケージを指定します。下記サンプルでは/usr/sbin/httpd
を起動するためhttpd
パッケージを指定しています。
-s
で指定されたパッケージの依存関係を表示します。# bin/v2c -p httpd -s * Resolving dependency for httpd... done! INFO: Total 115 package(s) found httpd shadow-utils audit-libs libcap-ng glibc glibc-common libselinux pcre glibc [*] libstdc++ libgcc glibc [*] libgcc [*] glibc [*] libsepol glibc [*] bash ncurses-libs libstdc++ [*] libgcc [*] ncurses-base glibc [*] glibc [*] bash [*] tzdata glibc [*] nss-softokn-freebl (...omit) INFO: [*]=Child dependencies are omitted as already described above.依存性ツリーの中で同じパッケージが繰り返し現れるため、表示済のパッケージの依存関係は省略されます。(末尾に"[*]"がついているパッケージ)
プロセスの起動に必要なファイルを一覧表示する
-l
で指定されたパッケージと、その依存パッケージに含まれるすべてのファイルを一覧表示します。(rpm -ql
で得られるもの)# bin/v2c -p httpd -l * Resolving dependency for bash... done! INFO: Total 41 package(s) found * Creating file list of 1 package(s) and its dependent packages... done! / /bin /bin/egrep /bin/fgrep /bin/grep /bin/sed /etc /etc/DIR_COLORS /etc/DIR_COLORS.256color /etc/DIR_COLORS.lightbgcolor /etc/GREP_COLORS /etc/X11 (...omit) /usr/share/man/ay/man7 (not found) /usr/share/man/ay/man7x (not found) /usr/share/man/ay/man8 (not found) (...omit) /var/run /var/run/setrans /var/spool /var/spool/lpd /var/spool/mail /var/tmp /var/yp INFO: Total 18684 file(s) found, however 13176 file(s) are not present in the file systemパッケージのファイルリストに含まれているものの、ファイルシステム内に存在しないファイルは末尾に"(not found)"がついています。
ユーザーが削除したファイルや、ghostファイルはすでにファイルシステムに存在しないためこのように表示しています。Dockerのイメージを作成する
-a
でDockerイメージを作成します。Webコンテンツとhttpdのユーザー設定ファイルを含めるため
-d <DIRECTORY>
オプションで/var/www/htmlと/etc/httpd/conf.dをアーカイブに含めるよう指定しています。# ./bin/v2c -p httpd -d /var/www/html -d /etc/httpd/conf.d -a * Resolving dependency for httpd... done! INFO: Total 115 package(s) found * Creating file list of 1 package(s) and its dependent packages... done! INFO: Total 23237 file(s) found, however 13193 file(s) are not present in the file system * Creating archive... done! INFO: Archive created in /tmp/archive.tgzDockerイメージとしてインポートする
生成したアーカイブはそのままDockerにインポートして、ベースイメージとして利用できます。
コンテナ起動時にパラメータを省略できるよう、エントリーポイントとコマンドパラメーターを含めています。
# docker image import /tmp/archive.tgz v2c-httpd:20190302 -c "ENTRYPOINT [\"/usr/sbin/httpd\"]" -c "CMD [\"-DFOREGROUND\"]" sha256:7908fb6eb6f50618c688a51556b0348de5948fe0a855aa32b515a74182ca1bbeコンテナを起動する
# docker run -d --rm -p 8080:80 v2c-httpd:20190302 32409c65c9c5ed96103333461eda513fe1d7c9b842dfc4ad17e22258e155e9e6ブラウザで http://DOCKERHOST:8080/ にアクセスするとApacheのTest Pageが表示されます。
/var/www/htmlに何かコンテンツを置いているのであればそれにアクセスすることもできます。ざっくりとした仕組み
Dockerはnamespaceやcgroupなどの技術を使って作成したサンドボックス内でプロセスを起動する技術です。そのためイメージの中に必要なファイルがそろっていればプロセスを起動できるはずです。
Dockerのドキュメントにベースイメージの作り方がありますが、これはdebootstrapでパッケージを展開してアーカイブで固めているだけです。
https://docs.docker.com/develop/develop-images/baseimages/
つまり逆に考えれば、実行中の環境でパッケージの依存性を解決して必要なファイルをすべて集めればDockerイメージを作ることが出来るはずです。(という思いつきからこのスクリプトを組んでみました)
v2c
コマンドはパッケージの依存ツリーを解決して(rpm -q --requires
,rpm -q --whatprovides
など)、依存パッケージのファイルをすべて集めて(rpm -ql
)、tgzに固めています。前述のとおりDockerのベースイメージは基本的に必要なライブラリやコマンド、設定ファイルをtarで固めただけなので、このイメージはそのままベースイメージとしてインポート可能です。
TODO
- パッケージに含まれるドキュメントファイルを除外できるようにする
- DEBパッケージ対応
- ベースイメージ + レイヤーイメージを作れるようにする。例えばベースイメージにはコアパッケージを含めておいて、レイヤーイメージにWebサーバーやMariaDBを起動するためのファイルを含めるような感じ。
- 投稿日:2019-03-02T14:13:22+09:00
Arch Linux インストールメモ
Just pasted
arch インストールメモ
構成
/dev/sda5 /boot 256MB vfat
/dev/sda6 / 40GB xfsmkfs.vfat -F32 /dev/sda5
mkfs.xfs -f /dev/sda6
mount /dev/sda6 /mnt
mkdir /mnt/boot
mount /dev/sda5 /mnt/boottimedatectl set-ntp true
vim /etc/pacman.d/mirrorlist
日本のServer行を上に移動させる
Tukuba, jaist, mirrorsの順wifi-menu
ip addresspacstrap /mnt base base-devel grub dosfstools efobootmgr netctl intel-ucode dialog
genfstab -U /mnt >> /mnt/etc/fstab
arch-chroot /mnt
ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
hwclock --systohc -utcvi /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.confecho lg-arch > /etc/hostname
vi /etc/hosts
127.0.0.1 localhost
::1 localhostmkinitcpio -p linux
bootctl --path=/boot install
vi /bootH/loader/loader.conf
default arch
timeout 4
editor 0
blkid >> /boot/loader/entries/arch.conf
vi /boot/loader/entries/arch.conf
title Arch Linux
linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /initramfs-linux.img
options root=PARTUUID=[sda6's PARTUUID] rwmkdir /backup
mount /dev/sda9 /backupcp /backup/netctl/* /cetc/netctl/
sudo systemctl disable dhcpcd.service
sudo systemctl enable netctl.servicepasswd
exit
rebootuseradd -mG wheel,audio,video,input matoruru
passwd matoruru
visudosu matoruru
mkdir ~/.config
cp -r /backup/chomium ~/.config/
chown -hR matoruru:matoriru chromiumexit
/etc/pacman.conf, multilibミラーのコメントアウトを外す
- 投稿日:2019-03-02T10:04:58+09:00
Ubuntu向けLinuxカーネルのdebパッケージ作成 (+perf, ftrace)
Ubuntu向けのLinuxカーネル関連debパッケージであるlinux-image, linux-headersに加えてlinux-tools(perf等が含まれる)を作成するための手順/スクリプトについて整理しています。
最新Linuxカーネルをビルドして適用したものの、カーネルバージョンの不一致によりperf, ftrace等を利用できず困ってる人向けです。
背景
Linuxカーネルはバージョンが上がる度に様々な機能、バグフィックス、最適化が加わります。また、パフォーマンスチューニングや解析のために必要なカーネル周りのメトリクス・ツール周りも積極的に強化されるため、新しいLinuxカーネルを積極的に導入&検証する方も多いと思います。
しかし新しいLinuxカーネルをビルドして適用した場合、perf, ftrace等のカーネル周りのイベント等を監視するためのツールもカーネルのバージョンに合わせて更新しなければ利用できなくなります。
apt/yum等のレポジトリに登録されているLinuxカーネルの場合、基本的にそのカーネルバージョンに対応するパッケージ(ex. linux-tools)が提供されているため特に問題はありません。
しかしそれ以外の手段(ex. Linux本家のソースコード、Ubuntu mailine ppa)でLinuxカーネルを適用する場合、perf, ftrace等がデフォルトでは含まれていなかったり、これらを含めるために結構色々な知識や試行錯誤が必要となることが多いです。Linuxカーネルの最新版を適用しても、perf, ftraceを利用できなければ解析や検証の幅が極めて狭くなってしまいます。
このため本記事では以下のものを利用して、linux-image, linux-headers等のdebパッケージに加えてlinux-toolsのdebパッケージを作成するための「Dockerを活用した手順/スクリプト」について記載しています。
- Linux本家のLinuxカーネル ソースコード
- Ubuntu mainline ppaのパッチファイル
前提
- ビルドマシン環境の前提
- Ubuntu 16.04 or 18.04
- Docker 18.09 (おそらく17.xxでも問題なし)
- ビルド実施者の前提
- Linuxカーネルのビルド、コンフィグ設定、インストール等ができることを想定。
- perf, ftrace等のツールの重要性を理解している。
- プロダクト環境等に導入する場合は、事前に十分な検証を行ったり、リスク評価を行ったりする必要があると十分に理解していることを想定。
ビルド手順
下記gistに手順および資材ファイルを載せています。
https://gist.github.com/yoichiwo7/70f81429813c5ec32cc620a950495b3e
手順はgistのREADME.mdにも記載していますが、簡単に日本語で記載しておきます:
gistにある
Dockerfile
とbuild-kernel-with-perf.sh
を同じディレクトリにダウンロードします。ダウンロードしたディレクトリにcdして、下記コマンドを実行してカーネルビルド用のDockerイメージを作成します。何故Dockerを使っているかは簡単に後ろの節で説明しています。
docker build -t kernel-build .Dockerイメージを作成後、Dockerコンテナを起動してカーネルをビルドします。コマンドの最後のパラメータはLinuxカーネルのバージョンなので、ビルドしたい適切なバージョンに適宜変更してください。
ちなみにLinuxカーネルのビルドには数時間レベルの時間がかかるので注意しましょう。
TARGET_KERNEL_VERSION="4.20.13" docker run \ --rm \ -u $(id -u):$(id -g) \ -v $PWD:/Output \ kernel-build $TARGET_KERNEL_VERSIONビルドが完了すると、同じディレクトリ配下に*.debのLinuxカーネル関連のdebパッケージが配置された状態となります。debパッケージは以下のコマンドでインストールすることができます。(インストール順は重要です)
dpkg -i linux-headers-* dpkg -i linux-modules-* linux-image-* dpkg -i linux-tools-*(補足) ビルド用Dockerイメージを使う理由
Linuxカーネルの各種debパッケージをビルドをするためには様々なUbuntuパッケージが必要となります。さらにUbuntuの16.04/18.04とかDesktop/Serverでも微妙に必要なパッケージ条件が異なる可能性があります。
このためDockerを使わずに様々なバージョンのUbuntu環境でカーネルビルドを実施すると、どうしても試行錯誤を繰り返しがちですし、Ubuntu環境自体に色々なパッケージがインストールされて汚れてしまいます。そして色々入れ過ぎたり設定したりした結果、何が正しいビルド条件なのかが把握できなくなることも珍しくはありません。
このため本手順ではカーネルビルド用のDockerイメージ(ベースイメージをubuntu 18.04に固定)を作成することで「より確実かつ環境を汚さず」にビルドを実施できるようにしています。
- 投稿日:2019-03-02T08:51:04+09:00
CDM(Console Display Manager) 導入の罠
背景
Arch Linux で3 年ほどDM として、xdm を使っていたのだが、 xdm に飽きてきたのとブラックボックス感があって中身をあまり知らなかったので、 よりシンプルなCDM を使ってみた。しかし、このCDM の導入は意外と 苦労したのでメモをするのと、DM がWM を開くまでの流れについて 考えてみた。
環境
- Linux 4.20.6 (arch Linux)
インストール
パッケージマネージャからインストールした。私はarch を使っているので
pacman
でインストール。# pacman -S cdm-git設定
CDM - ArchWiki に書いてある通りに設定すれば大丈夫だろ、と思っていたが、 結果X がうまく起動せず、AUR (en) - cdm-git のコメント、および cdm のgithub ページ を参照し、設定を行った。
~/.cdmrc
の作成・編集cdm の設定ファイルは、
/etc/cdmrc
(グローバル)、~/.cdmrc
(ユーザ個別) があるが、私は~/.cdmrc
をデフォルトの/etc/cdmrc
からコピーし、編集した。コメントが書いてあるので、コメント読んでいけば設定できるはず。 1つだけ注意すべきは、
~/.cdmrcxtty=keepとすること。cdm のgithub ページ によるとtty を変更するとX が立ち上がらない ようだ。
/etc/X11/Xwrapper.config
の作成・編集このファイルに関しては、AUR (en) - cdm-git のコメントを参照した。
/etc/X11/Xwrapper.config# for CDM needs_root_rights = yesこれがないと、VT が切り替えられない趣旨のエラーが起こり、X が起動しない。 VT を切り替えるにはルート権限が必要なようだ。
/usr/bin/cdm-xlaunch
の編集cdm のgithub ページ の変更を
/usr/bin/cdm-xlaunch
に適用する。 arch linux の場合のみ?では、これをしないとX が立ち上がらない。 大分前から知られていたようだが、まだこの変更はなぜかマージされていない ようだ…ログインからWM が立ち上がるまでの動き
ログインからWM(stumpwm を使用) が起動するまでの動きを
ps
にて調査した。 セッションID でフィルタを掛けている。ps -s "573 597 617" -j f [~] PID PGID SID TTY STAT TIME COMMAND 573 573 573 ? Ss 0:00 login -- kiso 597 597 597 tty1 Ss+ 0:00 \_ /bin/bash /usr/bin/cdm 614 597 597 tty1 S+ 0:00 \_ /bin/bash /usr/bin/cdm-xlaunch --startxlog /dev/null -- -- :0 -nolisten tcp vt1 617 617 617 ? Ss 0:00 \_ /bin/sh /usr/bin/startx -- :0 -nolisten tcp vt1 644 617 617 ? S 0:00 \_ xinit /home/kisoNas/.xinitrc -- /usr/bin/X :0 -nolisten tcp vt1 -auth /tmp/serverauth.zy0uczwWYy 645 645 617 ? Sl 0:18 \_ /usr/lib/Xorg :0 -nolisten tcp vt1 -auth /tmp/serverauth.zy0uczwWYy 649 649 617 ? S 0:01 \_ /usr/bin/stumpwm ︙コマンドの結果から、ログインからWM が立ち上がるまでは下記のような流れになっているようだ。
- コンソールにてログイン
zsh --login
(デフォルトシェルはzsh にしている)
/etc/zprofile
を実行/etc/zprofile# load cdm # To avoid potential situation where cdm(1) crashes on every TTY, here we # default to execute cdm(1) on tty1 only, and leave other TTYs untouched. if [[ "$(tty)" == '/dev/tty1' ]]; then [[ -n "$CDM_SPAWN" ]] && return # Avoid executing cdm(1) when X11 has already been started. [[ -z "$DISPLAY$SSH_TTY$(pgrep xinit)" ]] && exec cdm fi
exec cdm
により2 で実行したzsh --login
のプロセスに代わり、/bin/bash /usr/bin/cdm
のプロセスを実行する。
/usr/bin/cdm-xlaunch
内で/usr/bin/cdm-xlaunchsetsid startx "$@" > "$startxlog"により、新しいセッションID で
/bin/sh /usr/bin/startx -- :0 -nolisten tcp vt1が実行される。
X が5 で起動されたため、
~/.xinitrc
が読み込まれ、~/.xinitrcexec /usr/bin/stumpwmで
/usr/bin/stumpwm
でstumpwm のWM が実行される。文章にすると長くなってしまうが、動きとしてはシンプルだ。CDM だと
systemd
が絡まないのがよい。まとめ
CDM を導入するだけで大分ハマってしまったが、結果的にソースのgithub のページ で同じような不具合が起こっていないかを探すのがよかったようだ。 また、CDM に変えてよかったのは、bash で書かれているし、動き自体がシンプルで分かりやすかった ことだ。それと、CDM のメニュー画面で"シャットダウン"、"再起動"の機能を追加できたのもよい (xdm のときは、これら機能はなかった)。
- 投稿日:2019-03-02T05:36:05+09:00
Mattermost Team Edition のインストール
やってみたのでメモ
環境
OS・ミドルウェア バージョン OS CentOS Linux release 7.6.1810 (Core) PostgreSQL 11.2 Mattermost 5.8.0 前提
- PostgreSQL はインストール済みであること
データベース設定手順
postgres ユーザにログインする
# su - postgresPostgreSQL にログインする
$ psql psql (11.2) Type "help" for help.Mattermost 用 DB を作成する
postgres=# CREATE DATABASE mattermost; CREATE DATABASEMattermost 用 DB ユーザを作成する
postgres=# CREATE USER mmuser WITH PASSWORD '<パスワード>'; CREATE ROLEMattermost 用 DB にユーザアクセス権限を付与する
postgres=# GRANT ALL PRIVILEGES ON DATABASE mattermost to mmuser; GRANT
postgresql.conf
ファイルの設定を編集する# vi /var/lib/pgsql/11/data/postgresql.confpostgresql.conflisten_addresses = '*'
pg_hba.conf
ファイルの設定を編集する# vi /var/lib/pgsql/11/data/pg_hba.conf# TYPE DATABASE USER ADDRESS METHOD # "local" is for Unix domain socket connections only local all all trust # IPv4 local connections: host all all 127.0.0.1/32 md5 # IPv6 local connections: host all all ::1/128 md5 # Allow replication connections from localhost, by a user with the # replication privilege. local replication all trust host replication all 127.0.0.1/32 md5 host replication all ::1/128 md5Mattermost インストール手順
yumリポジトリを更新する
# yum updateバイナリファイルをダウンロードする(ダウンロードサイトからダウンロード)
# curl -LkvOf https://releases.mattermost.com/5.8.0/mattermost-5.8.0-linux-amd64.tar.gz破損がないか確認する(バージョン履歴を参照)
# sha256sum mattermost-5.8.0-linux-amd64.tar.gz f95c438c81171f6929c0f2438c358b7e1ccbd343546b2b3e75a5f9d14b0242cd mattermost-5.8.0-linux-amd64.tar.gz展開する
# tar -xvzf mattermost-5.8.0-linux-amd64.tar.gz展開したディレクトリを
/opt
配下に移動# mv mattermost /optデータ用ディレクトリを作成
# mkdir -p /opt/mattermost/dataMattermost 用ユーザを作成する
# useradd --system --user-group mattermostディレクトリの所有者を変更する
# chown -R mattermost:mattermost /opt/mattermostディレクトリの権限を設定する
# chmod -R g+w /opt/mattermost
config.json
ファイルを修正する# vi /opt/mattermost/config/config.json"SqlSettings": { "DriverName": "postgres", "DataSource": "postgres://mmuser:<mmuserのパスワード>@localhost:5432/mattermost?sslmode=disable\u0026connect_timeout=10", "DataSourceReplicas": null, "DataSourceSearchReplicas": null, "MaxIdleConns": 20, "ConnMaxLifetimeMilliseconds": 3600000, "MaxOpenConns": 300, "Trace": false, "AtRestEncryptKey": "h59xds1srgnbnj1849b5tat9xtf8kkex", "QueryTimeout": 30 },サービスファイルを作成する
# vi /usr/lib/systemd/system/mattermost.servicemattermost.service[Unit] Description=Mattermost After=syslog.target network.target postgresql-11.2.service [Service] Type=notify WorkingDirectory=/opt/mattermost User=mattermost ExecStart=/opt/mattermost/bin/mattermost PIDFile=/var/spool/mattermost/pid/master.pid TimeoutStartSec=3600 LimitNOFILE=49152 [Install] WantedBy=multi-user.targetサービスファイルの権限を修正する
# chmod 664 /usr/lib/systemd/system/mattermost.serviceサービスファイルを再読み込みする
# systemctl daemon-reload自動起動を設定する
# systemctl enable mattermost起動する
# systemctl start mattermost確認
次のURLにアクセスすると、Mattermost の画面が表示される
http://<IPアドレスもしくはホスト名>:8065参考