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

[VBA]UTF-8のファイルシステムの文字列が255以下であるか判定する関数とUTF-8の文字列をバイト単位でカウントする関数

AnsiからUTF-8へ

最初ANSIでのカウント方法から苦悩は始まり
Accessを始めるまえに簡単にパパッと作る関数ansiLenB Excelも
UTF-16LEのサロゲートペアにあい
発掘 サロゲートペアについて
Excel for Microsoft 365 VBA Win32Apiとスピルを使いすべての文字のUTF-16 UTF-8 SJisの文字コードを取得する
そして今

ファイル名の長さと文字コードの問題 プログラマー社長のブログ

まず、文字コードの問題があります。LinuxやMacOSでは、ファイル名は一般的にUTF-8です。WindowsはNTFSではUNICODEらしいのですが、アプリではShift_JIS(CP932)になるらしいです(あまり興味ないので・・・)。そのため、ZIPで固める際に、UTF-8のまま固めると文字化けしてしまいます。仕方ないので、LinuxやMacOSで無理矢理CP932のファイル名でファイルを作ってZIPで固めるとうまくいきます。が、MacOSでCP932のファイル名を作るとOSごと重くなることが多い気がするのでLinuxの方がマシです。。

さて、文字コードの問題をクリアーしたと思うと、今度はファイル名の長さの問題が立ちふさがります。Windowsではパスも含めて256文字までらしいので、長いファイル名はエラーになってしまいます。仕方ないので、長いファイル名は切り詰めるしかないのですが、ASCII文字の切り詰めは簡単ですが、マルチバイト文字の切り詰めは面倒です。適当なところで切ってしまうと文字化けしてしまいます。仕方ないので、C言語などではワイド文字に変換して切り詰めて、またマルチバイトに戻す感じになります。

昔はWindowsはCP932、UNIX系はEUCが多くて、どちらも日本語は2バイトという想定が使える場合が多かったのですが、インターネットが普及して世界各国の文字が共存するようになってきて、マルチバイトは2バイトどころではなくなってしまい、自力で何とかするのは大変になってしまいました。素直にマルチバイト処理ようのライブラリを使うのが良いでしょう・・・。

社長・・・

(中略)これでようやくWindowsで解凍できる見込みのファイル名にすることができます。「見込み」というのは、パスの長さが256文字までなので、展開するディレクトリによってはオーバーしてしまったりする可能性もあるためです。

ちなみに、LinuxなどのUNIX系OSでは、ファイル名の最大長は255バイト。パスの最大長は1023バイト(システムコールに渡す際の制限)と、Windowsよりはかなり扱いやすくなります

つまりLinuxサーバの場合
ファイル名は
文字コードはUTF-8で、
半角で255文字
ということになる。
この半角で255文字というのは全角文字は85字になる。
半角を1バイトとすると3バイトだからだ。
さらにサロゲートペアは4バイトである。
これを明らかにしたのが、
Excel for Microsoft 365 VBA Win32Apiとスピルを使いすべての文字のUTF-16 UTF-8 SJisの文字コードを取得する
こちらのSheetMake2から作成されるシートになる。
このWin32APIの判定精度の範囲では文字列はUTF-8のバイナリに変換される。
これを利用して、バイトでカウントするというものである。
今回も前回と同様、Win32APIを使う。下のコードは前回のものに追加した形で記述している。

#If VBA7 Then
Declare PtrSafe Function MessageBox Lib "user32" Alias "MessageBoxW" _
    (ByVal hwnd As LongPtr, ByVal lpText As LongPtr, _
     ByVal lpCaption As LongPtr, ByVal wType As Long) As Long
Declare PtrSafe Function GetFocus Lib "user32" () As LongPtr
Declare PtrSafe Function GetWindowsDirectory Lib "Kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
 Declare PtrSafe Function GetSystemDirectory Lib "Kernel32" Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
 Declare PtrSafe Function GetTempPath Lib "Kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
'Private Declare PtrSafe Function SetCurrentDirectory Lib "kernel32" (ByVal lpPathName As Long) As Long
' Set rrent Directory
Private Declare PtrSafe Function SetCurrentDirectory Lib "Kernel32" Alias _
                            "SetCurrentDirectoryA" (ByVal CurrentDir As String) As Long
'Private Declare PtrSafe Function SetCurrentDirectory Lib "kernel32.dll" Alias "SetCurrentDirectoryW" (ByVal lpPathName As Long) As Long
'Private Declare PtrSafe Function SetCurrentDirectory Lib "kernel32.dll" Alias "SetCurrentDirectoryA" (ByVal lpPathName As Long) As Long

#Else
'標準モジュールに以下のDeclare ステートメントを追加
Declare Function MessageBox Lib "user32" Alias "MessageBoxW" _
    (ByVal hwnd As Long, ByVal lpText As Long, _
     ByVal lpCaption As Long, ByVal wType As Long) As Long
Declare Function GetFocus Lib "user32" () As Long
Private Declare Function GetWindowsDirectory Lib "kernel32" _
 Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, _
 ByVal nSize As Long) As Long
#End If
Private Declare PtrSafe Function MultiByteToWideChar Lib "kernel32.dll" ( _
    ByVal CodePage As Long, _
    ByVal dwFlags As Long, _
    ByVal lpMultiByteStr As LongPtr, _
    ByVal cchMultiByte As Long, _
    ByVal lpWideCharStr As LongPtr, _
    ByVal cchWideChar As Long) As Long

Private Declare PtrSafe Function WideCharToMultiByte Lib "kernel32.dll" ( _
    ByVal CodePage As Long, _
    ByVal dwFlags As Long, _
    ByVal lpWideCharStr As LongPtr, _
    ByVal cchWideChar As Long, _
    ByVal lpMultiByteStr As LongPtr, _
    ByVal cchMultiByte As Long, _
    ByVal lpDefaultChar As LongPtr, _
    ByVal lpUsedDefaultChar As Long) As Long
Private Const CP_UTF8 = 65001

Private Const ERROR_INSUFFICIENT_BUFFER = 122&

'UFT-16LE SarrogatePairのコード
Sub TestSarrogatePair()
' For Excel
' ActiveCellにサロゲートペア文字が1字入っているとして、
' その上位サロゲートと下位サロゲートを求めて、試験のために
' MsgBoxExで表示する
' このため、Windows APIを使用する
' UTF-16 LE , BEなら bb(0) bb(1) bb(2) bb(3)になる
Dim b As String
Dim bb() As Byte
Dim Text As String
b = ActiveCell.Value
bb = b
Debug.Print "AscW Result(Dec -> Hex)" & vbTab & Hex(AscW(b))
Debug.Print "&H" & Hex(bb(1)) & Hex(bb(0))
Debug.Print "&H" & Hex(bb(3)) & Hex(bb(2))
Text = ChrW("&H" & Hex(bb(1)) & Hex(bb(0))) & ChrW("&H" & Hex(bb(3)) & Hex(bb(2)))
Debug.Print "ChrW(" & "&H" & Hex(bb(1)) & Hex(bb(0)) & ") & ChrW(&H" & Hex(bb(3)) & Hex(bb(2)) & ")"
MsgBoxEx Text
End Sub
'UTF-16 LE
Function UTF16Sarrogate(s As String)
Dim bb() As Byte
If IsUpperSarrogateCharacter(s) And IsLowerSarrogateCharcter(s) Then
bb = s
UTF16Sarrogate = "0x" & CStr(Hex(bb(1)) & Hex(bb(0))) & " " & "0x" & CStr(Hex(bb(3)) & Hex(bb(2)))
Exit Function
Else
UTF16Sarrogate = ""
End If
End Function
Function IsUpperSarrogateCharacter(s As String)
If Hex(AscW(s)) >= Hex(&HD800) And Hex(AscW(s)) <= Hex(&HDBFF) Then
IsUpperSarrogateCharacter = True: Exit Function
Else
IsUpperSarrogateCharacter = False: Exit Function
End If
End Function
Function IsLowerSarrogateCharcter(s As String)
Dim bb() As Byte
If IsUpperSarrogateCharacter(s) = True Then
bb = s
'Debug.Print Hex("&H" & bb(3) & bb(2))
If Hex("&H" & bb(3) & bb(2)) <= Hex(&HDC00) And Hex("&H" & bb(3) & bb(2)) <= Hex(&HDFFF) Then
IsLowerSarrogateCharcter = True: Exit Function
Else
IsLowerSarrogateCharcter = False: Exit Function
End If
End If
End Function
Function VBAAscW(s As String)
If AscW(s) < 0 Then
VBAAscW = AscW(s) + 65536: Exit Function
Else
VBAAscW = AscW(s): Exit Function
End If
End Function
' Shift-Jis
Function VBA_ASC(s As String)
If isSJIS(s) Then
VBA_ASC = Hex(Asc(s)): Exit Function
Else
VBA_ASC = "": Exit Function
End If
End Function
Function isSJIS(ByVal argStr As String) As Boolean
'https://excel-ubara.com/excelvba4/EXCEL_VBA_403.html
    Dim sQuestion As String
    sQuestion = Chr(63) '?:文字リテラルでは誤解があるといけないので
    Dim i As Long
    For i = 1 To Len(argStr)
        If Mid(argStr, i, 1) <> sQuestion And _
           Asc(Mid(argStr, i, 1)) = Asc(sQuestion) Then
            isSJIS = False
            Exit Function
        End If
    Next
    isSJIS = True
End Function
Function LenByteUTF8(ByRef s As String) As Long
    If Len(s) = 0 Then
        LenByteUTF8 = 0
        Exit Function
    End If
    Dim nBufferSize As Long
    Dim Ret() As Byte
    nBufferSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), 0, 0, 0, 0)
    ReDim Ret(0 To nBufferSize - 1)
    WideCharToMultiByte CP_UTF8, 0, StrPtr(s), Len(s), VarPtr(Ret(0)), nBufferSize, 0, 0
    LenByteUTF8 = UBound(Ret) + 1
End Function
Function IsLengthle255byteOnUTF8(s As String) As Boolean
' test版であり、検証中です
' UTF-8に変換し、Byte配列に代入し、個数をカウントする
' 255より大きい場合はFalse
' この関数を使う場合、
' https://qiita.com/Q11Q/items/a2d61545d9e5c4e15f22
' VBEの設定に注意してください
    If Len(s) = 0 Then
        IsLengthle255byteOnUTF8 = False
        Exit Function
    End If
    Dim nBufferSize As Long
    Dim Ret() As Byte
    Dim cnt As Long
    nBufferSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), 0, 0, 0, 0)
    ReDim Ret(0 To nBufferSize - 1)
    WideCharToMultiByte CP_UTF8, 0, StrPtr(s), Len(s), VarPtr(Ret(0)), nBufferSize, 0, 0
    cnt = UBound(Ret) + 1
    If cnt > 255 Then IsLengthle255byteOnUTF8 = False: Exit Function Else IsLengthle255byteOnUTF8 = True: Exit Function
End Function

前回のモジュールに追加する。
今回追加したのは
LenByteUTF8

Function LengthUTF8(s As String)
' test版であり、検証中です
' UTF-8に変換し、Byte配列に代入し、個数をカウントする
' 255より大きい場合はFalse
' この関数を使う場合、
' https://qiita.com/Q11Q/items/a2d61545d9e5c4e15f22
' VBEの設定に注意してください
    If Len(s) = 0 Then
        LengthUTF8 = 0
        Exit Function
    End If
    Dim nBufferSize As Long
    Dim Ret() As Byte
    Dim cnt As Long
    nBufferSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), 0, 0, 0, 0)
    ReDim Ret(0 To nBufferSize - 1)
    WideCharToMultiByte CP_UTF8, 0, StrPtr(s), Len(s), VarPtr(Ret(0)), nBufferSize, 0, 0
    cnt = UBound(Ret) + 1
    LengthUTF8 = cnt
End Function

とIsLengthle255byteOnUTF8
である。

Function IsLengthle255byteOnUTF8(s As String) As Boolean
' test版であり、検証中です
' UTF-8に変換し、Byte配列に代入し、個数をカウントする
' 255より大きい場合はFalse
' この関数を使う場合、
' https://qiita.com/Q11Q/items/a2d61545d9e5c4e15f22
' VBEの設定に注意してください
    If Len(s) = 0 Then
        IsLengthle255byteOnUTF8 = False
        Exit Function
    End If
    Dim nBufferSize As Long
    Dim Ret() As Byte
    Dim cnt As Long
    nBufferSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(s), Len(s), 0, 0, 0, 0)
    ReDim Ret(0 To nBufferSize - 1)
    WideCharToMultiByte CP_UTF8, 0, StrPtr(s), Len(s), VarPtr(Ret(0)), nBufferSize, 0, 0
    cnt = UBound(Ret) + 1
    If cnt > 255 Then IsLengthle255byteOnUTF8 = False: Exit Function Else IsLengthle255byteOnUTF8 = True: Exit Function
End Function

前回のtoUTF8からbyte単位のカウント方法が判る。

ReDim Ret(0 To nBufferSize - 1)
ここでバイト単位がカウントされている。
このまま出してもいいのかもしれないが、Win32APIの挙動がわからないので、確実に配列に代入する。
そしてUboundで取得した要素数に1を足す。
これも0ではなく Redimのときに1にしてよいのかもしれないが、この配列がWin32Apiに入るため、変えないほうがよいと判断した。

これはWindowsのサーバーのディレクトリやファイルの長さではありません

社長のブログにあるようにUTF-8で半角で255字、255バイトと言われるのはWindowsではなくLinuxであり、Windowsのサーバーのファイルの長さはこれでは測ることができない。

サロゲートペアは4バイト

このベースでカウントするとサロゲートペアは4バイト、半角で4文字消費する。
全角のように見えても、42文字が限界になると考えられる。
検索してみると5バイトや6バイトがあるとかあるけどはねられるとか諸説が見つかる。
IBMの資料を見てもUTF-8は最大で4バイトとしている。
https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.5.0/com.ibm.db2.luw.admin.nls.doc/doc/c0004816.html
このため、最大が4バイトとしておく。そして4バイトの例がサロゲートペアということになる。

バイトと文字数

今回の関数は文字列をUTF-8のバイト単位に換算している。それで全角も半角も関係なくコードに置き換えてその長さできまるようだ。
つまり容量としては255バイト、字数としては255字なので文中は使い分けている。

Win32APIと長所

たしかにコード的には長くなるがADODBを参照設定しなくていい。
また、toUTF8はUTF-8のバイト配列に変換してしまうため、スピルなどがなければ使いどころがなかった。
しかし、それはExcelのWorksheet上でしか有効ではないため、Excelでしか使いづらい。
今回の関数は字数をバイト数に変えたり、255文字を判定するため、Excelだけではなく、Access,Word,PublisehrOutlookでも活用が可能である。

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

Linux まとめ

コマンド

; $pwd;ls

左のコマンドでエラーが起きても成功しても右のコマンドを実行する。

&&  $ls prog/ruby && pwd

最初のコマンドが正常に終了した時だけ2番目のコマンド実行

|| $cat temp||echo "file not found"

最初のコマンドが正常に終了しなかった時だけ、2番目のコマンドが実行される。

() $(date;pwd;ls)>kekka.log

コマンドをまとめて実行

’’(シングルクォーテーション)

$echo $DATE
>8月31日
$echo '$DATE'
>$DATE
文字列として出力される。

""(ダブルクォーテーション)

$echo $DATE
>8月31日
$echo "今日の日付は$DATEです"
>今日の日付は8月31日です。
''と同じ。$の変数の部分は変数として出力される。

``(バッククォーテーション)

$echo"カレントディレクトリは'pwd'です。"
>カレントディレクトリは/home/lpicです。

$echo"カレントディレクトリは$(pwd)'です。"
>カレントディレクトリは/home/lpicです。

コマンド結果を出力できる。下の書き方の方がわかりやすいのでおすすめ。

less

キー操作 説明
スペースキー 下方向に1画面スクロール
bキー 上方向に1画面スクロール
/ 下方向検索
? 上方向検索

|(パイプ)

ls | wc -l
lsコマンドの実行結果をwcの標準入力に渡す。

dmesg|less
カーネルメッセージをlessの標準入力に渡す。

>(リダイレクト)

$ls -l > filelist
表示結果をfilelistにいれる。

>>

$ls -l >> filelist
表示結果をfilelistの末尾に追加。

<

$grep "lpic" result.txt
標準入力

$cat > sample.txt <<EOF
EOFが入力されるまで、出力。

2>

$find / -name "*.tmp" 2> error.log
エラー出力のみをファイルに保存。

cat

cat file1 file2 > newfile
応用:file1 file2をnewfileに連続して書き込む

オプション 説明
-n 行番号をつけて表示

nl

テキストファイルに行番号をつけて表示。

tail

最終行から10行表示。

オプション 説明
-n 行数 指定された行数だけ表示
-f リアルタイム表示。表示中に追加されたら更新する。(ctrl+cで終了)

tr

$cat /etc/hosts | tr 'a-z' 'A-Z'
ファイルの中の小文字を全て大文字に変換してcat

split

$split -100 sample.txt s_sample.

sample.txt s_sample.aa s_sample.ab s_sample.ac

sample.txtを100行ごとに他のファイルに分ける。
(ファイル名はaa,ab,ac...末尾につく)

ハッシュ

コマンド 説明
md5sum MD5によるハッシュ値を出力する
sha1sum
sha256sum
sha512sum

$sha1sum sample.txt
sample.txtファイルのSHA1ハッシュ値を表示

grep

$grep -i ab sample.txt

$grep -v '^#' /etc/httpd/conf/httpd.conf
冒頭に#がつく行(コメントアウト)を省いて表示。(^:初めの一文字目を表す正規表現)

オプション 説明
-i 大文字小文字を区別せず検索
-v パターンがマッチしない行を表示

vi

入力モード

コマンド 説明
i カーソルの前にテキストを入力する
a カーソルの後にテキストを入力する
I 行頭の最初の文字にカーソルを移動し、その直前にテキストを入力する
A 行末にカーソルを移動し、その直後にテキストを入力する
o カレント行の下に空白行を挿入し、その行でテキストを入力する
O カレント行の上に空白行を挿入し、その行でテキストを入力する

コマンドモード

コマンド 説明
h 1文字左へ移動する
l 1文字右へ移動する
k 1行上へ移動する
j 1行下へ移動する
o 行の先頭へ移動する
$ 行の末尾へ移動する
H 画面の一番上の行頭へ移動する
L 画面の一番下の行頭へ移動する
gg ファイルの先頭行へ移動する
G ファイルの最終行へ移動する
nG ファイルのn行目に移動する
:n ファイルのn行目に移動する

5hで5文字左に移動

コマンド 説明
:q ファイルへ保存せずに終了する
:q! 編集中の内容を保存せずに終了する
:wq 編集中の内容を保存して終了
:w 編集中の内容でファイルを上書き保存する
:e! 最後に保存した内容に復帰する
:! コマンド viを終了せずにシェルコマンドを実行する
:r! コマンド シェルコマンドの実行結果を挿入する

:!ls でviを動作させたまま、lsコマンドを実行できる。

viの編集コマンド

コマンド 説明
dd カレント行を削除
dw カーソル一から次の単語までを削除する
yy カレント行をバッファにコピーする
:w 編集中の内容でファイルを上書き保存する
p カレント行の下にバッファの内容を貼り付ける
P カレント行の上にバッファの内容を貼り付ける
x カーソル位置の文字を削除(delete)
X カーソル位置の手前の文字を削除(backspace)

5dd でカーソル位置から5行削除。

viの検索コマンド

コマンド 説明
/ カーソル位置から後ろ方向に向かって検索
? カーソル位置から後ろ方向に向かって検索
n 次を検索する
N 次を検索する(逆方向)
:noh 候補のハイライト表示を解除する
:%s/A/B/ 最初に見つかった文字列Aを文字列Bに置換する
:%s/A/B/g 全ての文字列Aを文字列Bに置換する
コマンド 説明
:set nu 行番号を表示する
:set nonu 行番号をh非表示する
:set ts=タブ幅 タブ幅を数値で指定する

ファイル管理

gzip

コマンド 説明
-d 圧縮ファイルを展開する
-c 標準出力へ出力
-r ディレクトリ内のファイル全て圧縮する

$gzip datafile
ファイルを圧縮

$gzip -r sampled
sampledディレクトリ内にある全てのファイルを個々に圧縮

$gzip -c datafile >datafile.gz
圧縮前のフォルダも残し圧縮

$bzip2 datafile
bzipはgzipよりも時間がかかるが圧縮効率は高い。
(解凍は オプション -dをつける)

$xz datafile
xzはbzipよりも時間がかかるが圧縮効率は高い。
(解凍は オプション -dをつける)

zcat,bzcat,xzcat

$zcat sample.gz
圧縮されたテキストファイルを解凍せずに確認する。

tar

ファイルやディレクトリを1つのアーカイブファイルにまとめたり、それを展開できる。
zオプションでgzip圧縮と同じ。

コマンド 説明
-c アーカイブを作成する
-x アーカイブからファイルを取り出す
-t アーカイブの内容を確認する
-f ファイル名 アーカイブファイル名を指定する
-z gzip 圧縮/展開
-j bzip2 圧縮/展開
-J xz 圧縮/展開
-v 詳細な情報を表示する
-u アーカイブ内にある同名のファイルより新しいものだけを追加する
-r アーカイブにファイルを追加する
-N 指定した日付より新しいデータのみを対象とする
-M 複数デバイスへの分割
-delete アーカイブからファイルを削除する

tar cvf /dev/st0 /home
/homeのアーカイブファイルを /dev/st0に作成

tar xvzf software.tar.gz
アーカイブファイルをカレントディレクトリに展開。

tar tf /dev/sdb1
/dev/sb1にあるアーカイブの内容を表示する。

tar xvf /dev/sdb1 var/log/secure
/var

cpio

$ls | cpio -o >/tmp/backup
カレントディレクトリを/tmp/backupファイルとしてバックアップ。

dd

$dd if=/dev/sdb of=/dev/sdc
/dev/sdbに接続されたディスクの内容をそのまま/dev/sdbに出力。

ddコマンドは、ハードディスクやCD-ROMなどのデバイスの内容をそのまま扱える。
cpコマンドは、ファイルをコピーするだけ。

コマンド 説明
-if 入力側ファイルを指定する
-of 出力側ファイルを指定する

chmod

オプション 説明
-R 指定したディレクトリ以下にある全ファイルのアクセス権を変更する
対象 説明
u 所有者
g グループ
o その他ユーザー
a 全てのユーザー
操作 説明
+ 権限を追加する
- 権限を削除する
= 権限を指定する
許可の種別 説明
r 読み取り許可
w 書き込み許可
x 実行許可
s SUID or SGID
t スティッキービット

$chmod go+w samplefile
グループとその他ユーザーに書き込み権限を与える

$chmod o-rw samplefile
その他ユーザーから書き込み実行権限をなくす

$chmod 644 samplefile
644に変更

SUID,SGID

SUID ファイルの所有者の権限で実行可能

chmod u+s samplefile

SGID グループのアクセス権が適用される。

スティッキービット

書き込み権限はあっても、自分以外のユーザーが所有するファイルを削除できない。

chmod o+t sampledir

umask

デフォルトのアクセス権が決められている。

$umask
0002

ディレクトリは777からファイルは666からumaskを引いた権限がデフォルト

d→775 file→664

chown

オプション 説明
-R 指定したディレクトリとその中にある全ファイルの所有者を変更する

ハードリンク

それぞれのファイルで同一の実体を参照する。
$ln file.original file.link_hard

シンボリックリンク

リンク下の場所を示す。(ショートカット)
$ln -s file.original file.link_hard

ls -l
作成したリンクを確認。

シンボリックリンクのコピーにはdをつける。

cp -d file.link_sym file.link3

付けないとリンク元のファイルがコピーされる。
cp file.link_sym file.link2

top

プロセスの監視
Qで終了

バックグラウンドジョブの実行

updatedb &
&を付けることでバックグラウンドで処理を実行できる。

jobs
jobsコマンドで実行中のジョブを確認できる。

長時間にわたって席を外す場合などで実行し続けげ欲しい。
ログアウトしても実行していて欲しい場合。
nohubを付ける。
$nohup updatedb &

現在実行しているジョブをバックグラウンドで行いたい場合。
ctrl + zで一時停止 → bg 1
(1はジョブの番号 jobsでわかる)
バックグラウンドをフォアグラウンドに変えたいときはfg

free

メモリの空き状況

オプション 説明
-m MB単位で表示する
-s 秒 指定した間隔で表示し続ける

uptime

平均負荷など

uname

OSの確認

uname -a
詳細表示

watch

watch -n 10 uptime
10秒ごとにuptimeを実行。

nice

コマンド実行時の優先度指定。
$nice -n -10 updatedb

デバイス管理ファイル管理

find

$find /root -name "*.txt"
ファイル名で検索

検索式 説明
-name ファイル名 ファイル名で検索する
-atime 日時 最終アクセス時刻で検索する
-mtime 日時 最終更新時刻で検索する
-perm アクセス権 アクセス権で検索する
-size サイズ ファイルサイズで検索する
-type ファイルの種類 ファイルの種類で検索するf:ファイル l:シンボリック d:ディレクトリ
-user ユーザー名 ファイルの所有者で検索する
-print マッチしたファイルを表示する
-exec コマンド || ¥; マッチしたファイルに対してコマンドを実行
-ok コマンド || ¥; マッチしたファイルに対してコマンドを実行(確認あり)

$find /data -type f -mtime -1
過去1日以内に更新されたファイルを検索

$find /usr/bin -type f -perm -u+s
/usr/binディレクトリ以下からSUIDが設定されたファイルを検索。

$find /tmp -user student
所有者がstudentであるファイルディレクトリを検索。

$find -atime +30 -exec rm {}¥;
30日を超える日数の間アクセスされていないファイルを検索し、削除。

シェルとシェルスクリプト

エイリアス

$alias ls='ls -l'
コマンドに別名をつけることができる。
$alias lsless='ls -l|less'

$unalias lsless
設定されているエイリアスを解除

関数

$function lslink(){ls -l|grep '^l';}
シンボリックリンク (lから始まる)のみを表示するlslink関数

$function lslink(){ls -l $1 | grep '^1';}
$1で引数。引数にディレクトリなどを入れれる。

$declare -f lslink
定義されている関数のみを表示。

unset lslink
lslink関数を削除。

bashの設定ファイル

ファイル 説明
/etc/profile ログイン時に実行され、全ユーザーから参照される
/etc/bash.basic bash起動時に実行され、全ユーザーから参照される
/etc/bashrc ~/.bashrcから参照される bash起動時から参照。
~/.bash_profile ログイン時に実行される
~/.bash_login ~/.bash_profileがない場合、ログイン時に実行される
~/.profile ~/.bash_profileも~/.bash_loginもない場合、ログイン時に実行
~/.bashrc bash起動時に実行される
~/.bash_logout ログアウト時に実行される

シェルスクリプト

実行(読み取り権限必要)
$bash lsld

$source lsld

$. lsld

(実行権限必要)
chmod a+x lsld
$./lsls
そのままファイル名で実行される。

変数名 説明
$0 シェルスクリプトファイル名(フルパス)
$1 1番目の引数
$2 2番目の引数。以下$3$4$5
$# 引数の数。
$@ 全ての引数(スペース区切り)
$* 全ての引数(区切りは環境変数IFSで指定されたもの)

実行結果の戻り値

正常終了→0
異常終了→0以外

$echo $?
2

戻り値は$?に代入される。

ファイルのチェック

testコマンド

条件式 実行結果
ファイル形式のテスト
-f ファイル (ディレクトリなどを除く)ファイルがあれば真
-d ディレクトリ ディレクトリがあれば真
-r ファイル ファイルが存在し、かつ読み込み可能であれば真
-w ファイル ファイルが存在し、かつ書き込み可能であれば真
-x ファイル ファイルが存在し、かつ実行可能であれば真
-s ファイル サイズが0より大きいファイルがあれば真
-L ファイル シンボリックリンクであるファイルがあれば真
ファイル特性のテスト
-e ファイル ファイルがあれば真
ファイル1 -nt ファイル2 ファイル1がファイル2より修正時刻が新ければ真
ファイル1 -ot ファイル2 ファイル1がファイル2より修正時刻が古ければ真
数値のテスト
数値1 -eq 数値2 数値1と数値2が等しければ真
数値1 -ge 数値2 数値1が数値2より大きい、もしくは等しければ真
数値1 -gt 数値2 数値1が数値2より大きければ真
数値1 -le 数値2 数値1が数値2より小さい、もしくは等しければ真
数値1 -lt 数値2 数値1が数値2より小さいもしくは等しければ真
数値1 -ne 数値2 数値1と数値2が等しくなければ真
文字列のテスト
-n 文字列 文字列の長さが0より大きければ真
-z 文字列 文字列の長さが0であれば真
文字列1=文字列2 2つの文字列が等しければ真
文字列1!=文字列2 2つの文字列が等しくなければ真
テストの論理結合
!条件 条件が偽であれば真
条件1 -a 条件2 両方の条件式が真であれば真(and)
条件1 -o 条件2 いずれかの条件式が真であれば真(or)

条件分岐

if 条件式
then
実行文1
else
実行文2
fi

Case

case $1 in
1)echo "January";;
2)echo "February";;
esac

read

名前を標準入力から聞くことができる。
echo -n "Who are you?:"
read username ←ここでユーザーに聞いて
echo "Hello,$username!" ←ここで使う

シェルスクリプトの1行目
#!/bin/bash

管理タスク

ユーザーアカウント設定されているファイル
/etc/passwd

グループ
/etc/group

useradd

useradd -c "Linux User" -d /home/linux -s /bin/bash linuxuser

オプション 実行結果
-c コメント コメントフィールドを指定
-d ディレクトリ ホームディレクトリを指定
-s パス デフォルトシェルを指定

ジョブスケジューリング

cron

crontab
/var/spool/cron ディレクトリ以下に置かれる。

オプション 実行結果
-e crontabを編集(直接viなどで開いてはいけない)
-l 内容表示
-r ファイル削除
-i 削除時に確認する
-u ユーザー名 ユーザー名を指定してcrontabファイルを編集(rootユーザーのみ)

書式
分 時 日 月 曜日 コマンド

フィールド 実行結果
曜日 0-7までの整数(0,7:日曜〜6土曜)

15 23 * * * /usr/local/bin/backup
(毎日23:15に起動)

0 9,12 * * 1 /usr/local/bin/syscheck
(月曜の09:00と12:00に起動)

0 */2 * * * /usr/local/bin/syscheck
(2時間ごとに起動)

at

一回限りのスケジューリング
$at 5:00 tomorrow
at>/usr/local/sbin/backup
at>^D ←ctrl+Dキーを入力で終了。

systemd

何らかのイベントから一定時間後に発動などができる。

メール

mail[-s題名][宛先メールアドレスorユーザー名]

mail -s samplemail student
Hello!Student!  ←本文
.
EOT

mail
受信メールを確認

ネットワークの基礎

ping

オプション 実行結果
-c 回数 指定した回数だけパケット送信
-i 間隔 指定した間隔(秒)ごとにポケット送信

traceroute

指定されたホストまでパケットが伝わる経路を表示。

hostname

現在のホスト名を表示。

ホスト名を指定した場合、ホスト名を変更。

netstat

ネットワークの様々な情報を表示。
開いているポートの確認など。

nc

ネットワーク上のcatコマンド

$nc -l -p 12345 -o listen.log
12345番ポートで待ち受けし、受け取ったデータをlisten.logファイルに出力。

$nc centos7.example.com 12345<data.txt
ホストの12345ポートに対し、data.txtファイルの内容を出力。

ifconfig

ipアドレスの確認。

DNSの設定ファイル

/etc/resolv.conf

/etc/nsswitch.conf
hostsを優先するかDNSサーバーを優先するかの順序を選択。

host

ホストのipがわかる。ipのホストがわかる。

セキュリティ

nmap

$nmap www.example.net
開いているポート番号とサービス名(ssh,http)が確認できる。

SUIDが設定されているファイルを確認する方法。

定期的に確認を行うべし。
#find / -perm -u+s -ls

一般ユーザーのログインを停止する

#touch /etc/nologin
nologinファイルを作成しておくことで、ルート以外のログイン以外は禁止される。

scp

scp コピー元ファイル名 [ユーザー名@] コピー先ホスト:[コピー先ファイル名]

scp /etc/hosts sv3.example.jp:/tmp
ローカルホストの/etx/hostsをリモートホストsv3.example.jpの/tmp以下にコピー。

scp  [ユーザー名@]コピー元ホスト:コピー元ファイル名 コピー先ファイル名

$scp sv3.example.jp:/etc/hosts .
リモートホストsv3.example.jpの/etc/hostsをカレントディレクトリにコピー。

$scp data.txt fred@sv3.example.jp:
リモートホストsv3.example.jpのfredユーザーのホームディレクトリにローカルホストのdata.txtファイルをコピー

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

小プロセスを含めたkill

概要

小プロセスを含め、killをするためのツールです。python用です。
(pythonのプロセスで縛りを掛けています。)
検証はlinuxのみしてあります。

使い方は、
そのまま実行すると、小プロセスを持つ親プロセスの一覧が表示されるので、
(例としてproc_01.py proc_02.pyの小プロセスを持つプログラムが実行中とします。)

$ python terminate_children_process.py

python 関連の小プロセスを持つprocess一覧
コマンドラインにPIDを指定すると、小プロセスを含めてterminate します。
{'pid': 26727, 'cmdline': ['python', 'proc_01.py']}
{'pid': 26747, 'cmdline': ['python', 'proc_02.py']}

終了させたいpidを指定し再び実行します。

$ python terminate_children_process.py 26747

terminate 子プロセス 26849
terminate 子プロセス 26850
terminate 子プロセス 26851
terminate  親プロセス 26747

ソース(terminate_children_process.py)

#terminate_children_process.py
import sys
import psutil

if len(sys.argv)==1:
    #python 関連の小プロセスを持つprocessの表示
    print("python 関連の小プロセスを持つprocess一覧")
    print("コマンドラインにPIDを指定すると、小プロセスを含めてterminate します。")

    PROCNAME = "python"
    for proc in psutil.process_iter([ "pid"  ,  'cmdline'  ]):
        if proc.name()[:len(PROCNAME)] == PROCNAME:
            p = psutil.Process(proc.pid)
            if len(p.children()) >0:
                print(proc.info)

else:
    #指定したPIDとその小プロセスを含めてterminate

    target_pid=int(sys.argv[1])
    p = psutil.Process(target_pid)

    #子のterminate
    pid_list=[pc.pid for pc in p.children(recursive=True)] 
    for pid in pid_list:
        psutil.Process(pid).terminate ()
        print("terminate 子プロセス {}" .format(pid))

    #親のterminate
    p.terminate ()
    print("terminate  親プロセス {}" .format(target_pid))

参考

psutil documentation

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

【Linux】ファイル検索

はじめに

Linuxでファイル検索する方法をメモ

  • ファイル名で検索
  • 特定の文字列を含むファイルを検索
  • 高速でファイル検索

環境情報

  • OS:Redhat 7.7

ファイル検索

ファイル名で検索

find 【検索ディレクトリ】 -type f -name 【ファイル名】

特定の文字列を含むファイルを検索

grep [検索したい文字列] -rl [検索ディレクトリ]

高速でファイル検索

locateデータベースを更新する

sudo updatedb
※ スーパーユーザーで実行
locate -b 【検索キーワード】
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JVNVU#97690270 (RPMB脆弱性)を簡単に確認してみた

この記事はLinux Advent Calendar 2020の5日目です。

TL;DR

  • Replay Protected Memory Block (RPMB) プロトコルでは、共通鍵を利用して、HostとDevice間で処理するデータについて検証する手段。
  • ところが、今回指摘した脆弱性を使うと 「Hostには失敗と応答されたのに、Deviceではデータが書かれている」「Hostには成功と応答されたのに、Deviceはデータを書いていない」 というケースが作れそう。
  • Linux Kernel本体にはRPMBへアクセスするための直接的なロックは存在してない。mmc-utils上でにコマンドラインから呼び出すコードがある。

はじめに

想定される影響
RPMB プロトコルを利用するシステムに直接アクセス可能な第三者によって、次のような影響を受ける可能性があります。
・RPMB 領域への書込みが成功したにも関わらず失敗したようにホストに誤認識させる
・RPMB 領域にホストの意図とは異なる内容を書き込んだにも関わらず、意図通りの内容を書き込んだとホストに誤認識させる

このあたりをもうちょっと読み解いていく!

そもそもReplay Attackとは?

雑に説明すると、こんな感じ。詳細は、Wikipediaの反射攻撃 を参考ください。

  • 悪意ある人間が認証情報ごと丸ごとコピーすると、正規要求なのか不正要求なのかわからなくなる。
    • 下記の例だと「社長」の判子がある要求には、「経理」は正規要求だと認識して、現金を手渡す。
    • では、社長の作った書類を悪い人が盗聴・複製して、コピーを経理に渡したら?
    • 経理の人は本物と偽物の見分けがつかないので、現金を支払ってしまう。
    • 社長が見ると「あれ?これ・・・なんで2回10万円?」と悩む。

image.png

Replay Protected Memory Block (RPMB) プロトコルとは?

Replay Protected Memory Block (RPMB) protocol does not adequately defend against replay attacksからリンクが張られていた、Western Digital社のe.MMC Security Methods を基に確認してみる。

  • HostとDeviceでそれぞれ暗号鍵情報を分けて持っている。
  • Read OnlyなCounterがあることで、Replay Attackをすると必ずMACがズレて失敗する。

Western Digital社のwhite-paper-emmc-security.pdfから引用。

image.png

今回の攻撃は?

wdc-20008-replay-attack-vulnerabilities-rpmb-protocol-applications にリンクが張られているwhite-paper-replay-protected-memory-block-protocol-vulernabilities.pdf 詳細が記載されているので、これを紹介したい。

Case 1 : データ書いているけど、書かなかったことにする

振る舞い

image.png

  • (1) Hostは、REQ( カウンタCt, アドレスAdr, MAC Mを、Device) を送信。
  • (2) 敵(adversary) が、Host->Device間の通信に割り込む!!
    • 敵は、失敗するようにMAC値を書き換えたREQ* を Deviceに送信、
  • (3) Deviceは検証をするけど、MAC値不正で失敗をHostへ返却。
    • 失敗しているので、Device側のカウンタ値は更新されない。
    • Hostは失敗が通知されたので「失敗した」と認識する。
  • (4) 敵は、REQをDeviceに送信。
  • (5) DeviceはREQを検証し、カウンタCtもMAC Mも正しいので成功と判断してデータを書き換える。

結果

  • Host 「え?REQを送ってみたけど、失敗したよ。データは書き換わってないはずだよ」
  • Device「REQ*は失敗したけど、REQは成功したよ。データは書き換わっているよ!」

という感じで、認識の相違が発生する!!!怖いですねー

Case 2 : データ書いていないけど、書いたことにする

振る舞い

image.png

  • (1) Hostは、REQ1( Ct, Data1, Adr, M1) を送信。
    • 敵(adversary) が、Host->Device間の通信に割り込む!!
    • 敵は、REQ1を記録しておく。
  • (2) 状態の喪失:例えば電源切断
  • (3) 復帰:例えば再起動
  • (4) Hostは、REQ2( Ct, Data2, Adr, M1) を送信。
    • 敵(adversary) が、Host->Device間の通信に割り込む!!
  • (5) 敵は、REQ2ではなく、REQ1をDeviceへ送信!
  • (6) DeviceはREQ1を検証し、カウンタCtもMAC Mも正しいので成功と判断してデータを書き換える。成功をHostへ返却。

結果

  • Device「REQ1の要求受けたから、そのData1でちゃんと書き換えましたよ!成功しました!」
  • Host 「REQ1の応答がなかったような…。。。 でも、最後に送信したREQ2に対しては成功が帰ってきたから、Data2で書き換えられているはずです!」

あらららら……

Linux KernelのRPMB実装を確認してみよう!

からサポートが始まっている………… と、思うじゃろ?

https://lkml.org/lkml/2016/11/7/674

このスレッドから始まる議論では、この修正は含まれなかった。
その結果、RPMBへアクセスするためのインタフェイスは存在していない、と。

えええ、じゃあどうやってアクセスするのかー、っというところで、見るべきポイントは「mmc-utils」です。

mmc-utils

https://git.kernel.org/ にちゃーんとリンクが張られている。

image.png

https://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc-utils.git/

ここで、データを書き込むコマンド、do_rpbm_write_block()に閉じて、その振る舞いを確認していく!と思ったけど、大体話は上で書いたものとそう大差さないので、最後にAppendixとしてまとめておきます。

予備知識

  • mmc rpmb write-key </path/to/mmcblkXrpmb> </path/to/key>
    • HostからDeviceへ鍵情報を書き込める。
  • mmc rpmb read-counter </path/to/mmcblkXrpmb>
    • HostはDeviceからカウンタ情報を読み出せる。
  • mmc rpmb read-block </path/to/mmcblkXrpmb> <address> <blocks count> </path/to/output_file> [/path/to/key]
    • HostはDeviceから、指定した鍵情報keyを利用して、指定したアドレスaddressからblock_countの数だけの内容を読み取り、output_fileへ出力できる。
  • mmc rpmb write-block </path/to/mmcblkXrpmb> <address> </path/to/input_file> </path/to/key>
    • HostはDeviceへ、指定した鍵情報keyを利用して、指定したアドレスaddressへinput_fileの内容を書き出せる。

考察

  • mmc-utilsの実装コードを見ていると、確かにHost/Device間でカウンター値の連続性とかチェックが無い。
    • TCPのシーケンス番号もないから、確かにCase2のようにその応答が今回のコマンド要求に対する応答かどうかとかもわからないなあ…
    • つまり、プロトコルレベルでの設計で、問題があったんだなあと…。
  • RPMBに重要な情報を保持するとわかっていると、ここを集中して狙われそう。確かにこれはまずい…。

まとめ (再掲)

お忙しい中、ここまで読んでいただき、ご精読頂き、ありがとうございました!!

以下のようにまとめます。

  • Replay Protected Memory Block (RPMB) プロトコルでは、共通鍵を利用して、HostとDevice間で処理するデータについて検証する手段。
  • ところが、今回指摘した脆弱性を使うと「Hostには失敗と応答されたのに、Deviceではデータが書かれている」「Hostには成功と応答されたのに、Deviceはデータを書いていない」というケースが作れそう。
  • Linux Kernel本体にはRPMBへアクセスするための直接的なロックは存在してない。mmc-utils上でにコマンドラインから呼び出すコードがある。

補足…

Appendix (mmc-utilsの実装確認)

https://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc-utils.git/tree/mmc_cmds.c?id=73d6c59af8d1bcedf5de4aa1f5d5b7f765f545f5#n2263

このコードを簡単に読んでいく。

各種変数定義

書き込むREQを格納する、struct rpbm_frame frame_in を定義する。

mmc_cmds.c
int do_rpmb_write_block(int nargs, char **argv)
{
    int ret, dev_fd, key_fd, data_fd;
    unsigned char key[32];
    uint16_t addr;
    unsigned int cnt;
    struct rpmb_frame frame_in = {
        .req_resp    = htobe16(MMC_RPMB_WRITE),
        .block_count = htobe16(1)
    }, frame_out;

/dev/mmcblkXrpmbを開く。

dev_idは、/dev/mmcblkXrpmbのfilr descriptor。

mmc_cmds.c
    if (nargs != 5) {
        fprintf(stderr, "Usage: mmc rpmb write-block </path/to/mmcblkXrpmb> <address> </path/to/input_file> </path/to/key>\n");
        exit(1);
    }

    dev_fd = open(argv[1], O_RDWR);
    if (dev_fd < 0) {
        perror("device open");
        exit(1);
    }


カウンターの値をdeviceから読み出す

mmc_cmds.c
    ret = rpmb_read_counter(dev_fd, &cnt);
    /* Check RPMB response */
    if (ret != 0) {
        printf("RPMB read counter operation failed, retcode 0x%04x\n", ret);
        exit(1);
    }
    frame_in.write_counter = htobe32(cnt);

アドレス情報をセットする

mmc_cmds.c
    /* Get block address */
    errno = 0;
    addr = strtol(argv[2], NULL, 0);
    if (errno) {
        perror("incorrect address");
        exit(1);
    }
    frame_in.addr = htobe16(addr);

データや鍵情報をファイル/標準入力から読み出す

mmc_cmds.c
    /* Read 256b data */
    if (0 == strcmp(argv[3], "-"))
        data_fd = STDIN_FILENO;
    else {
        data_fd = open(argv[3], O_RDONLY);
        if (data_fd < 0) {
            perror("can't open input file");
            exit(1);
        }
    }

    ret = DO_IO(read, data_fd, frame_in.data, sizeof(frame_in.data));
    if (ret < 0) {
        perror("read the data");
        exit(1);
    } else if (ret != sizeof(frame_in.data)) {
        printf("Data must be %lu bytes length, but we read only %d, exit\n",
               (unsigned long)sizeof(frame_in.data),
               ret);
        exit(1);
    }

    /* Read the auth key */
    if (0 == strcmp(argv[4], "-"))
        key_fd = STDIN_FILENO;
    else {
        key_fd = open(argv[4], O_RDONLY);
        if (key_fd < 0) {
            perror("can't open key file");
            exit(1);
        }
    }

    ret = DO_IO(read, key_fd, key, sizeof(key));
    if (ret < 0) {
        perror("read the key");
        exit(1);
    } else if (ret != sizeof(key)) {
        printf("Auth key must be %lu bytes length, but we read only %d, exit\n",
               (unsigned long)sizeof(key),
               ret);
        exit(1);
    }

これまでの書き込みデータの内容から、HMACの値を計算する

mmc_cmds.c
    /* Calculate HMAC SHA256 */
    hmac_sha256(
        key, sizeof(key),
        frame_in.data, sizeof(frame_in) - offsetof(struct rpmb_frame, data),
        frame_in.key_mac, sizeof(frame_in.key_mac));

REQを送信するためのRPMB 処理を実行し、結果を確認する

mmc_cmds.c
    /* Execute RPMB op */
    ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1);
    if (ret != 0) {
        perror("RPMB ioctl failed");
        exit(1);
    }

    /* Check RPMB response */
    if (frame_out.result != 0) {
        printf("RPMB operation failed, retcode 0x%04x\n",
               be16toh(frame_out.result));
        exit(1);
    }

後始末

mmc_cmds.c
    close(dev_fd);
    if (data_fd != STDIN_FILENO)
        close(data_fd);
    if (key_fd != STDIN_FILENO)
        close(key_fd);

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

スタンドアローン状態のUbuntuにネットワークドライバをインストールする方法

背景

  1. Among usっていうゲームやりたくてUbuntuのProtonの設定をいじってました。
  2. GPUのドライバがインストールできてなかったことに気づきました。
  3. 適当な以下のコマンド打ってみました。
sudo ubuntu-drivers autoinstall

ネットワークとサウンドが死にました。
もともと、マザーボードのEthernetソケットはドライバインストールが面倒だったので、USB-NICを使ってました。USB-NICは普通に認識できてたのですが、上記操作でそれすら使えなくなりました。なんか他にやっちゃったのか?
ま、とりあえず回復しましょう。
この際なので、マザーボードのEthernetソケット用に設定しましょう。

状況調査

以下で現在のカーネルバージョンを調べました。

$ uname -r
5.4.0-54-generic

次に、ネットワークチップの種類を調べました。

$ lspci | grep Ether
06:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)

realtek RTL8125ですね。
所定の場所にドライバが存在するか調べました。すでに調べたカーネルVerのディレクトリ配下です。

$ls /lib/modules/5.4.0-54-generic/kernel/drivers/net/ethernet/realtek/
8139cp.ko  8139too.ko

RTL8125は無いですね。
こいつを作る必要があります。
RTL8125ドライバ生成用ファイル群は以下Realtek公式ページで取得できます。
https://www.realtek.com/en/component/zoo/category/network-interface-controllers-10-100-1000m-gigabit-ethernet-pci-express-software

以下が使えました。
Screenshot from 2020-11-22 13-57-46.png

Makefile、autorun.shの中身からドライバの生成にはmake、gccコマンドが必要だとわかるのですが、残念ながらそれらはインストールされていません。ネットも使えないのでapt installもできません。なので別のサブPCでドライバ生成し、それをUSBドライブで持ってくることとします。

環境

メインPC:

詳細 備考
OS Ubuntu 20.04
CPU AMD Ryzen 9 3900XT
network chip Realtek RTL8125

サブPC:

詳細 備考
OS Ubuntu 18.04
CPU Intel(R) Core(TM) i5-8400

サブPC作業手順

  1. VirtualBox上で、Ubuntu20.04をインストールし、uname -rでカーネルVerがメインPCと同一であることを確認。1回目は違ったので、upgradeしたら同一になりました。他の記事など参考にしてください。これとか

  2. 先述の公式ファイル群をVirtualBox上でダウンロードし、そのフォルダにて./autorun.shを実行します。おそらくなにか足りない旨の表示がありますが、3の手順でドライバが生成されてれば問題ないです。

  3. VirutualBox上で以下を実行し、r8125.koがあることを確認。

$ ls /lib/modules/5.4.0-54-generic/kernel/drivers/net/ethernet/realtek/
8139cp.ko  8139too.ko  atp.ko  r8125.ko  r8169.ko

4.VirutualBox上からサブPCにr8125.koを移動。これはscpや共有フォルダなどで移動してください。

5.USBドライブを使ってr8125.koをサブPCからメインPCの以下フォルダに移動。

/lib/modules/5.4.0-54-generic/kernel/drivers/net/ethernet/realtek/

メインPC作業手順

  1. 以下コマンドで一時的にドライバとして適用。
 $ sudo insmod /lib/modules/5.4.0-54-generic/kernel/drivers/net/ethernet/realtek/r8125.ko

2.数秒後、ネットワークが復活していることを確認。

3.確認できたら、再起動後も有効化されるように以下コマンドを打つ。

sudo depmod -a

以上。

(おまけ)サウンド復活方法。

設定の音声のOutputDeviceにて、Dummy Outputのみが出力されている状態でした。
以下コマンドを打ってみました。inxiはaptでインストールしました。

$ inxi -SMA
System:
  Host: ueda-System-Product-Name Kernel: 5.4.0-54-generic x86_64 bits: 64 
  Desktop: Gnome 3.36.4 Distro: Ubuntu 20.04.1 LTS (Focal Fossa) 
Machine:
  Type: Desktop Mobo: ASRock model: B550M Steel Legend 
  serial: <superuser/root required> BIOS: American Megatrends v: P1.10 
  date: 06/11/2020 
Audio:
  Device-1: NVIDIA GP107GL High Definition Audio driver: N/A
  Device-2: AMD Starship/Matisse HD Audio driver: N/A 
  Sound Server: ALSA v: k5.4.0-54-generic

AudioのdriverがN/Aになってます。
このdriverは以下コマンド実行でインストールされました。

sudo apt install linux-modules-extra-`uname -r`

もう一度見てみます。

$ inxi -SMA
System:
  Host: ueda-System-Product-Name Kernel: 5.4.0-54-generic x86_64 bits: 64 
  Desktop: Gnome 3.36.4 Distro: Ubuntu 20.04.1 LTS (Focal Fossa) 
Machine:
  Type: Desktop Mobo: ASRock model: B550M Steel Legend 
  serial: <superuser/root required> BIOS: American Megatrends v: P1.10 
  date: 06/11/2020 
Audio:
  Device-1: NVIDIA GP107GL High Definition Audio driver: snd_hda_intel 
  Device-2: AMD Starship/Matisse HD Audio driver: snd_hda_intel 
  Sound Server: ALSA v: k5.4.0-54-generic

driverがsnd_hda_intelになって、音も出るようになりました。

あとがき

7年ほどUbuntu縛り生活をしてきて、ネット断絶は良く発生してました。その度毎にOS再インストールなどのダサい回避策を行ってきていましたが、上記対応が出来たことでUbuntistとしてレベルアップした気がします。
今回はVirtualBoxでクロスコンパイル的にドライバを生成しましたが、makeの引数指定でスマートに生成出来たかもしれませんね。作業中調べてもなかなかヒットしなかったのでその方法は諦めました。詳しい人いたら教えてください。

make,gccはOSインストール直後にやっておくべきですね。そうしたら、メインPCでコンパイルすれば良いだけの話になってたので。

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

Docker Desktop for WindowsをLinux(WSL)で操作

概要

WindowsにインストールしたDocker DesktopをWindowsにインストールしたLinux ディストリビューション(Ubuntu)で利用するためのセットアップ手順をメモ

さっくりまとめると、
なんらかのLinux ディストリビューションをインストールしたら
Docker Desktop の設定で WSL の統合を有効化するだけ

Linux ディストリビューション(Ubuntu)のインストール

基本以下を見ればOK
Windows 10 用 Windows Subsystem for Linux のインストール ガイド

手順4までは、すでにDocker Desktopのセットアップを行っていれば、その際に実施済みのはず

手順 5 - WSL 2を既定のバージョンとして設定する

PowerShellでコマンド実行
wsl --set-default-version 2

メモ:WSL1とWSL2の違いについて1

手順 6 - 選択した Linux ディストリビューションをインストールする

今回はUbuntu 20.04 LTSをインストール

Ubuntuを起動

初回起動時はusernameとpasswordを聞かれるので、任意の名前とパスワードを入力すればそのまま登録される
新しい Linux ディストリビューションのユーザー アカウントとパスワードを作成する

パッケージの更新とアップグレード

とりあえず、お約束
sudo apt update && sudo apt upgrade

dockerコマンド打ったら通らない、、、

満を持してWindows上のLinuxからdockerコマンド実行したが、期待した動きではないような、、

$ docker --version

The command 'docker' could not be found in this WSL 2 distro.
We recommend to activate the WSL integration in Docker Desktop settings.

See https://docs.docker.com/docker-for-windows/wsl/ for details.

Docker Desktopの設定をしてねという事らしい

Docker Desktop の設定で WSL の統合を有効化

DockerのSettings > Resources > WSL INTEGRATION でインストールしたLinuxディストリビューションへの統合を有効化
image.png

アプリを再起動

統合を有効化したら、Ubuntuアプリを再起動して改めてdockerコマンド実行したらdockerコマンド実行OK

$ docker --version
Docker version 19.03.13, build 4484c46d9d

これで、晴れてWindows上のDockerをWindows上のLinuxから操作できる


  1. WSL1とWSL2の違いについて WSL 1 と WSL 2 の比較の機能比較によるとWSL2は完全なLinuxカーネルとシステムコールの完全な互換性があり、WSL1と比較してzipファイルの展開が最大20倍早いとのこと、WindowsとLinux間でファイルのやり取りをする必要がある場合WSL1を利用するとよい場合もある模様  

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