- 投稿日:2020-05-21T19:11:08+09:00
arch/arm/kernel/swp_emulate.cの中身も読む
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm/kernel/swp_emulate.c
そもそも、swpエミュレーションってなんで必要なの?
簡単にまとめると、
(1) もともと2レジスタ間でデータを交換するSWP命令が存在していた。
(2) マルチコアCPUになったところ、別CPUとの排他制御が必要になった
(3) 上位層にSWP命令使うな、といいたい。だけど、そうも言ってられないので、Kernel側でソフトエミュレーションする仕組みが必要になった。ですね……。
なお、データ交換するxchg命令は、x86などの別のアーキテクチャでも存在します。
ARM社ドキュメントへのリンク
SWP命令
- http://infocenter.arm.com/help/topic/com.arm.doc.100069_0610_01_en/pge1425914080521.html
- http://infocenter.arm.com/help/topic/com.arm.doc.dui0801cj/pge1425914080521_00004.html
LDREX命令 / STREX命令
- http://infocenter.arm.com/help/topic/com.arm.doc.100069_0610_01_en/pge1425890318276.html
http://infocenter.arm.com/help/topic/com.arm.doc.dui0801cj/pge1425890318276_00004.html
http://infocenter.arm.com/help/topic/com.arm.doc.100069_0610_01_en/pge1425890604489.html
http://infocenter.arm.com/help/topic/com.arm.doc.dui0801cj/pge1425890604489_00003.html
1. 起動時にtrap.cにSWP emurationを登録
swp_emulate.c から traps.c にフック関数の登録依頼
起動時に、
late_initcall(swp_emulation_init);
→swp_emulation_init()
→register_undef_hook()
ちうコールチェーンになって、swp_handler()がundef_hookで登録される。arch/arm/kernel/swp_emulate.c"/* * Only emulate SWP/SWPB executed in ARM state/User mode. * The kernel must be SWP free and SWP{B} does not exist in Thumb/ThumbEE. */ static struct undef_hook swp_hook = { .instr_mask = 0x0fb00ff0, .instr_val = 0x01000090, .cpsr_mask = MODE_MASK | PSR_T_BIT | PSR_J_BIT, .cpsr_val = USR_MODE, .fn = swp_handler ★★★★★ココ }; /* * Register handler and create status file in /proc/cpu * Invoked as late_initcall, since not needed before init spawned. */ static int __init swp_emulation_init(void) { if (cpu_architecture() < CPU_ARCH_ARMv7) return 0; #ifdef CONFIG_PROC_FS if (!proc_create_single("cpu/swp_emulation", S_IRUGO, NULL, proc_status_show)) return -ENOMEM; #endif /* CONFIG_PROC_FS */ pr_notice("Registering SWP/SWPB emulation handler\n"); register_undef_hook(&swp_hook); ★★★★★ココ return 0; } late_initcall(swp_emulation_init); ★★★★★ココtrap.c は、hook関数を登録する。
arch/arm/kernel/traps.c で登録する。
arch/arm/kernel/traps.cvoid register_undef_hook(struct undef_hook *hook) { unsigned long flags; raw_spin_lock_irqsave(&undef_lock, flags); list_add(&hook->node, &undef_hook); raw_spin_unlock_irqrestore(&undef_lock, flags); }2. trap発動(させるまで)
ベクタテーブル -> kernelまで
雑に説明すると、ベクターテーブルでundef instructionを見つけると、フック関数に登録しておいたswpのエミュレーション関数が呼ばれる。
arch/arm/kernel/entry-armv.Svector_rst: ARM( swi SYS_ERROR0 ) THUMB( svc #0 ) THUMB( nop ) b vector_und <略> /* * Undef instr entry dispatcher * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC */ vector_stub und, UND_MODE .long __und_usr @ 0 (USR_26 / USR_32) .long __und_invalid @ 1 (FIQ_26 / FIQ_32) .long __und_invalid @ 2 (IRQ_26 / IRQ_32) .long __und_svc @ 3 (SVC_26 / SVC_32) ★★★★★★★★★★★ ココ!! .long __und_invalid @ 4 .long __und_invalid @ 5 .long __und_invalid @ 6 .long __und_invalid @ 7 .long __und_invalid @ 8 .long __und_invalid @ 9 .long __und_invalid @ a .long __und_invalid @ b .long __und_invalid @ c .long __und_invalid @ d .long __und_invalid @ e .long __und_invalid @ f .align 5 <略> .align 5 __und_svc: #ifdef CONFIG_KPROBES @ If a kprobe is about to simulate a "stmdb sp..." instruction, @ it obviously needs free stack space which then will belong to @ the saved context. svc_entry MAX_STACK_SIZE #else svc_entry #endif @ @ call emulation code, which returns using r9 if it has emulated @ the instruction, or the more conventional lr if we are to treat @ this as a real undefined instruction @ @ r0 - instruction @ #ifndef CONFIG_THUMB2_KERNEL ldr r0, [r4, #-4] #else mov r1, #2 ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2 cmp r0, #0xe800 @ 32-bit instruction if xx >= 0 blo __und_svc_fault ldrh r9, [r4] @ bottom 16 bits add r4, r4, #2 str r4, [sp, #S_PC] orr r0, r9, r0, lsl #16 #endif badr r9, __und_svc_finish mov r2, r4 bl call_fpe mov r1, #4 @ PC correction to apply __und_svc_fault: mov r0, sp @ struct pt_regs *regs bl __und_fault ★★★★★★★★★★★ ココ!! __und_svc_finish: get_thread_info tsk ldr r5, [sp, #S_PSR] @ Get SVC cpsr svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__und_svc) <略> __und_fault: @ Correct the PC such that it is pointing at the instruction @ which caused the fault. If the faulting instruction was ARM @ the PC will be pointing at the next instruction, and have to @ subtract 4. Otherwise, it is Thumb, and the PC will be @ pointing at the second half of the Thumb instruction. We @ have to subtract 2. ldr r2, [r0, #S_PC] sub r2, r2, r1 str r2, [r0, #S_PC] b do_undefinstr ★★★★★★★★★★★★★★★★★ ココ!! ENDPROC(__und_fault)kernel → hook関数
さて、これで無事に
do_undefinstr
が呼び出される。
ここでは、すでに事前登録されたhook関数を呼び出す関数を呼び出す(めんどい言い方ですが…)arch/arm/kernel/traps.csmlinkage void do_undefinstr(struct pt_regs *regs) { unsigned int instr; void __user *pc; pc = (void __user *)instruction_pointer(regs); if (processor_mode(regs) == SVC_MODE) { <略> instr = __mem_to_opcode_arm(*(u32 *) pc); } else if (thumb_mode(regs)) { if (get_user(instr, (u16 __user *)pc)) goto die_sig; instr = __mem_to_opcode_thumb16(instr); if (is_wide_instruction(instr)) { unsigned int instr2; if (get_user(instr2, (u16 __user *)pc+1)) goto die_sig; instr2 = __mem_to_opcode_thumb16(instr2); instr = __opcode_thumb32_compose(instr, instr2); } } else { if (get_user(instr, (u32 __user *)pc)) goto die_sig; instr = __mem_to_opcode_arm(instr); } if (call_undef_hook(regs, instr) == 0) ★★★★★★★ココ return; <略> } NOKPROBE_SYMBOL(do_undefinstr)
call_undef_hook()
から、hookに登録したある関数が呼び出される。arch/arm/kernel/traps.cstatic nokprobe_inline int call_undef_hook(struct pt_regs *regs, unsigned int instr) { struct undef_hook *hook; unsigned long flags; int (*fn)(struct pt_regs *regs, unsigned int instr) = NULL; raw_spin_lock_irqsave(&undef_lock, flags); list_for_each_entry(hook, &undef_hook, node) if ((instr & hook->instr_mask) == hook->instr_val && (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) fn = hook->fn; raw_spin_unlock_irqrestore(&undef_lock, flags); return fn ? fn(regs, instr) : 1; }3. trap発動!!
さて、それではフック関数が呼ばれたら、に入ります。
/* * swp_handler logs the id of calling process, dissects the instruction, sanity * checks the memory location, calls emulate_swpX for the actual operation and * deals with fixup/error handling before returning */ static int swp_handler(struct pt_regs *regs, unsigned int instr) { unsigned int address, destreg, data, type; unsigned int res = 0; perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->ARM_pc); res = arm_check_condition(instr, regs->ARM_cpsr); switch (res) { case ARM_OPCODE_CONDTEST_PASS: break; case ARM_OPCODE_CONDTEST_FAIL: /* Condition failed - return to next instruction */ regs->ARM_pc += 4; return 0; case ARM_OPCODE_CONDTEST_UNCOND: /* If unconditional encoding - not a SWP, undef */ return -EFAULT; default: return -EINVAL; } if (current->pid != previous_pid) { pr_debug("\"%s\" (%ld) uses deprecated SWP{B} instruction\n", current->comm, (unsigned long)current->pid); previous_pid = current->pid; } address = regs->uregs[EXTRACT_REG_NUM(instr, RN_OFFSET)]; data = regs->uregs[EXTRACT_REG_NUM(instr, RT2_OFFSET)]; destreg = EXTRACT_REG_NUM(instr, RT_OFFSET); type = instr & TYPE_SWPB; pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n", EXTRACT_REG_NUM(instr, RN_OFFSET), address, destreg, EXTRACT_REG_NUM(instr, RT2_OFFSET), data); /* Check access in reasonable access range for both SWP and SWPB */ if (!access_ok((address & ~3), 4)) { pr_debug("SWP{B} emulation: access to %p not allowed!\n", (void *)address); res = -EFAULT; } else { res = emulate_swpX(address, &data, type); } if (res == 0) { /* * On successful emulation, revert the adjustment to the PC * made in kernel/traps.c in order to resume execution at the * instruction following the SWP{B}. */ regs->ARM_pc += 4; regs->uregs[destreg] = data; } else if (res == -EFAULT) { /* * Memory errors do not mean emulation failed. * Set up signal info to return SEGV, then return OK */ set_segfault(regs, address); } return 0; }3.1 arm_check_condition
現状の状態で、当該命令を実行するべきかどうかの判断。
- ARM_OPCODE_CONDTEST_FAIL - 実行する必要なし。
- ARM_OPCODE_CONDTEST_PASS - 実行しなければならない。
- ARM_OPCODE_CONDTEST_UNCOND - Never あるいは…
arch/arm/kernel/opcodes.c/* * Returns: * ARM_OPCODE_CONDTEST_FAIL - if condition fails * ARM_OPCODE_CONDTEST_PASS - if condition passes (including AL) * ARM_OPCODE_CONDTEST_UNCOND - if NV condition, or separate unconditional * opcode space from v5 onwards * * Code that tests whether a conditional instruction would pass its condition * check should check that return value == ARM_OPCODE_CONDTEST_PASS. * * Code that tests if a condition means that the instruction would be executed * (regardless of conditional or unconditional) should instead check that the * return value != ARM_OPCODE_CONDTEST_FAIL. */
3.2 emulate_swpX()
arch/arm/kernel/swp_emulate.cstatic int emulate_swpX(unsigned int address, unsigned int *data, unsigned int type) { unsigned int res = 0; // TYPE_SWPBの場合、アドレスがunalignedだとエラー if ((type != TYPE_SWPB) && (address & 0x3)) { /* SWP to unaligned address not permitted */ pr_debug("SWP instruction on unaligned pointer!\n"); return -EFAULT; } // 他と調停しながら、__user_swp[b]_asm()を呼び出す。 // resが-EAGAINだったらやり直し。 while (1) { unsigned long temp; unsigned int __ua_flags; __ua_flags = uaccess_save_and_enable(); if (type == TYPE_SWPB) __user_swpb_asm(*data, address, res, temp); else __user_swp_asm(*data, address, res, temp); uaccess_restore(__ua_flags); if (likely(res != -EAGAIN) || signal_pending(current)) break; cond_resched(); } // カウンタアップ if (res == 0) { if (type == TYPE_SWPB) swpbcounter++; else swpcounter++; } return res; }3.3 user_swp[b]_arm()
arch/arm/kernel/swp_emulate.c/* * Error-checking SWP macros implemented using ldrex{b}/strex{b} */ #define __user_swpX_asm(data, addr, res, temp, B) \ __asm__ __volatile__( \ "0: ldrex"B" %2, [%3]\n" \ "1: strex"B" %0, %1, [%3]\n" \ " cmp %0, #0\n" \ " moveq %1, %2\n" \ " movne %0, %4\n" \ "2:\n" \ " .section .text.fixup,\"ax\"\n" \ " .align 2\n" \ "3: mov %0, %5\n" \ " b 2b\n" \ " .previous\n" \ " .section __ex_table,\"a\"\n" \ " .align 3\n" \ " .long 0b, 3b\n" \ " .long 1b, 3b\n" \ " .previous" \ : "=&r" (res), "+r" (data), "=&r" (temp) \ : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ : "cc", "memory") #define __user_swp_asm(data, addr, res, temp) \ __user_swpX_asm(data, addr, res, temp, "") #define __user_swpb_asm(data, addr, res, temp) \ __user_swpX_asm(data, addr, res, temp, "b")読みやすく書き直してしまうと
ldrexとstrexでデータ交換しているだけになる(後半部分はよくわからないね!)
-EAGAINを介したら、上位層emulate_swpX()で成功するまでリトライされる。0: ldrex"B" %temp, [addr] # [addr]の内容を、tempに読み出す 1: strex"B" %res, %data, [addr] # dataの内容を、[addr]に書き出す # resはアップデートされたら0, アップデートできなければ1 cmp %res, #0 # resが0であるかを判断 moveq %data, %temp # true => tempの内容をdataに書き出す movne %res, -EAGAIN # false => res = -EAGAIN 2: .section .text.fixup,"ax" .align 2 3: mov %res, -EFAULT b 2b .previous .section __ex_table,"a" .align 3 .long 0b, 3b .long 1b, 3b .previous : "=&r" (res), "+r" (data), "=&r" (temp) : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) : "cc", "memory" )以上です。
- 投稿日:2020-05-21T13:30:06+09:00
Linux基礎3-ファイル操作の基本-
今回は、ファイルの作成・コピー・削除などのLinuxのファイルの基本操作を記事にします。
ファイル操作のコマンドを覚えてしまえば、マウスでのクリックが不便に思えてくるかも知れません。mkdirコマンド
新しくディレクトリを作成するには、mkdirを使用する
mkdirコマンド$ mkdir [オプション] <作成するディレクトリ名>下の図では、ホームディレクトリにworkディレクトリを作成し、lsコマンドで作成したworkディレクトリを確認しています。
lsコマンドのオプションについてはLinuxコマンドリファレンスを参照ください。
今回は-Fと-wを指定しています。
すでに同名のファイルが存在する場合にはmkdirは失敗する
下の図では、すでにworkディレクトリが存在している場所に、workディレクトリの作成コマンドを入力した結果です。
mkdirは 「同名のディレクトリが存在します」 とエラーを返します。
深いディレクトリを一気に作成したい場合
何階層もある深いディレクトリを作成したい場合があります。
このときmkdirの-pオプションを指定することで、存在しない親ディレクトリも含めて、ディレクトリを作成できます。
下の図では、mkdirをオプションなしで実行した場合と、-pオプションを指定して実行した場合の結果を示しています。-pオプションを指定しない場合、mkdirはエラーを返しますが、-pオプションを指定することで深い階層のディレクトリを作成できます。
touchコマンド
Linuxでファイルを作成する方法はたくさんありますが、ここではtouchコマンドを使用します。
touchコマンド$ touch <新しいファイル名1> <新しいファイル名2> ...touchコマンドは中身のないファイルを作成します。複数ファイルを同時に作成したい場合には、スペースで区切って並べます。
本来touchコマンドはファイルのタイムスタンプ(日時)を更新するためのコマンドです。しかし、対象のファイルが存在しない場合には、新しくファイルを作成するという動きをするため、単純に空のファイルを作成するためにも使用できます。
touchコマンドでのファイルの作成は、誤って既存のファイル名を指定しても、内容が上書きされたり、削除されないため安心です。rmとrmdirコマンド
rmコマンド
rmコマンドはファイルを削除するコマンドです。
rmコマンド$ rm [オプション] <削除するファイル名1> <削除するファイル名2> ...複数のファイルを削除したい場合は、touch同様、スペースで区切って並べます。
rmでディレクトリの削除
rmでディレクトリを削除するには再帰的にディレクトリツリーを削除する-rオプションを指定します。
このとき、削除対象のディレクトリ内のファイルやディレクトリもまとめて削除しますので注意が必要です。
※注意
rmコマンドを実行するとファイルは本当に削除されてしまうため実行前には必ず削除していいものかどうか確認しましょう。WinやMacのようなゴミ箱はありません。rmdirコマンド
rmと似たコマンドにrmdirというコマンドがあります。これは空のディレクトリを削除するコマンドです。
rmdirコマンド$ rmdir <ディレクトリ名>rmコマンドは中にファイルのあるディレクトリを削除しようとしてもエラーとなる点がrmコマンドとの大きな違いです。
.hiddenのような隠しファイルがディレクトリ内に残っている場合にもrmdirコマンドでの削除はエラーが返ってきます。
rmdirコマンドを使うと中にファイルが存在するディレクトリを誤って削除することを防げます。
catコマンド
catコマンドはファイルの中身を表示するコマンドです。
catコマンド$ cat [オプション] <ファイル名1> <ファイル名2> ...作成したばかりのnewfileには中身がないため、catを実行しても何も表示されませんが、中身のあるファイルを指定するとその内容を表示します。
複数のファイルを指定した場合、その中身を連結して(連続で)表示します。
行番号を表示する
catコマンドでよく使用されるオプションに -n があります。これは行番号をつけて内容を表示するオプションです。
ファイルを指定しない場合
catコマンドでファイルを指定しない場合は、キーボードからの入力を待機するようになります。
catコマンド(引数なし)$ cat #引数なしでコマンド実行 Hello #Helloと入力した Hello #Helloと表示される #Ctrl+dを入力(キーボード入力終了) $ #プロンプトが戻るcatだけでなく、多くのLinuxコマンドは入力ファイルを指定しない場合、キーボードからの入力を待機します。この利用方法については後の記事で紹介します。
lessコマンド
catコマンドは単にファイルの中身をそのまま表示するだけでした。そのため表示したい内容が多い場合には、1画面に収まりきらなくなります。このような長いファイルをみたい場合にはlessコマンドを使用します。
lessコマンド$ less [オプション] <ファイル名>lessコマンドはファイルの内容を1画面ごとに表示して、画面を上下にスクロールすることができます。
lessコマンドのスクロール操作
コマンド 内容 スペースキー、f、Ctrl+v 1画面下にスクロールする b、Meta+v 1画面上にスクロールする j、Ctrl+n、Enter 1行下にスクロールする k、Ctrl+p 1行上にスクロールする q lessコマンドを終了する ファイル内の検索
lessコマンドでは現在開いているファイルから文字列を検索することができます。
ファイルを表示中に「/」を入力すると、一番下の行が検索文字列の入力欄に変わります。
文字列を入力してEnterを叩くことで検索されます。lessコマンドの検索操作
コマンド 内容 /<文字列> 下方向に向かって検索する ?<文字列> 上方向に向かって検索する n 次の検索結果に移動する N 前の検索結果に移動する 下の図は、lessコマンドの検索機能でetcという文字列を検索しています。
cpコマンド
ファイルをコピーするためにはcpコマンドを使用します。
cpコマンド$ cp [オプション] <コピー元> ... <コピー先>下の図では、newfileをnewfile2としてコピーしています。
また、ファイルをディレクトリへコピーすることもできます。これはnewfileをdir1へコピーしています。
複数のファイルをディレクトリにコピーする場合は、コピー元のファイルをスペース区切りで並べて、最後の引数にコピー先のディレクトリを指定します。
コピーの際の上書き確認
cpコマンドはコピー先に同名のファイルが存在していたとしても、確認せずに上書きしてしまいます。
ここで-iオプションをつけるとコピー先のファイルが存在する場合に、上書きしても良いかを確認してくれます。[y/n]で回答しましょう。
ディレクトリのコピー
cpコマンドではディレクトリをコピーしようとするとエラーになります。
そのため、ディレクトリをコピーする場合は再帰的にコピーを実行する-rオプションを指定します。
このとき、コピー先のディレクトリが存在していない場合には、指定した名前でディレクトリをコピーします。
一方、コピー先のディレクトリが存在している場合には、コピー先にディレクトリを指定したと受け取られて、コピー元をコピー先のディレクトリにコピーします。
mvコマンド
ファイルやディレクトリを移動するにはmvコマンドを使用します。
mvコマンド$ mv [オプション] <移動元> ... <移動先><移動元><移動先>にファイルを指定した場合は、ファイル名の変更をしているのと同義になります。
cpとは異なり、移動元からファイルがなくなることに注意してください。
また、移動先に同名のファイルが存在する場合には、上書きされてしまう点にも注意してください。-iオプションを指定することで、cp同様、上書き前に確認メッセージを表示できます。lnコマンド
lnコマンドはリンクを貼るコマンドです。
lnコマンド$ ln [オプション] <リンク元ファイル名> <リンク名>リンクとは
Linuxのファイルシステムでは、ファイルに別名をつけることができます。この機能をリンクと呼びます。
リンクには「ハードリンク」「シンボリックリンク」の2種類があります。「ハードリンク」の使用は限定的で、「シンボリックリンク」が頻繁に使用されます。ハードリンクとは
ハードリンクの使用
中身がhelloと表示されるfile1のハードリンクfile2を作成しました。
その後$ cat file2を実行するとfile1と同じ内容が表示されていることがわかります。
意味合いとしては、file1、file2の両方とも、本物の名前と言えます。
ハードリンクの削除
ハードリンクをもつファイルの実態は、全てのハードリンクがなくなったときに削除されます。
先ほど作成したハードリンクfile2の元であったfile1を削除しましたが、file2は実体をもっていることが下の図からわかります。
シンボリックリンクとは
ハードリンクはディレクトリに対して作成できない、異なるディスク間を跨がることができないという制限があります。一方で、シンボリックリンクはこのような制限を受けないため、シンボリックリンクの方が頻繁に使用されます。
シンボリックリンクとは、リンク先のパス名が書かれた小さな特殊ファイルです。
ハードリンクとは異なり、リンク元のファイルが実体です。
シンボリックリンクの使用
シンボリックリンクを使用するにはlnコマンドに-sオプションを指定します。
helloと表示するfile1にシンボリックリンクfile2を作成しました。$ cat file2で表示されているのはfile1の内容(hello)です。ls -lで詳細情報を表示するとfile2->file1のように、どのファイルへパスを示しているかが確認できます。
シンボリックリンクの削除
シンボリックリンクはrmコマンドで削除することができます。
シンボリックリンクの実体である元ファイルを削除するとシンボリックリンクは残されますが、リンクが壊れた状態になります。
このときシンボリックリンクを開いても実体がないためエラーを返されます。
シェルの設定によっては赤い警告でリンクが壊れたことを教えてくれます。
リンクの利用方法
リンクには次のような使い道があります。参考までに。
長いパス名を省略する$ ln -s local/work/code/project/source source $ cd source参考資料
- 投稿日:2020-05-21T13:30:06+09:00
Linux基礎4 -ファイル操作の基本-
今回は、ファイルの作成・コピー・削除などのLinuxのファイルの基本操作を記事にします。
ファイル操作のコマンドを覚えてしまえば、マウスでのクリックが不便に思えてくるかも知れません。mkdirコマンド
新しくディレクトリを作成するには、mkdirを使用する
mkdirコマンド$ mkdir [オプション] <作成するディレクトリ名>下の図では、ホームディレクトリにworkディレクトリを作成し、lsコマンドで作成したworkディレクトリを確認しています。
lsコマンドのオプションについてはLinuxコマンドリファレンスを参照ください。
今回は-Fと-wを指定しています。
すでに同名のファイルが存在する場合にはmkdirは失敗する
下の図では、すでにworkディレクトリが存在している場所に、workディレクトリの作成コマンドを入力した結果です。
mkdirは 「同名のディレクトリが存在します」 とエラーを返します。
深いディレクトリを一気に作成したい場合
何階層もある深いディレクトリを作成したい場合があります。
このときmkdirの-pオプションを指定することで、存在しない親ディレクトリも含めて、ディレクトリを作成できます。
下の図では、mkdirをオプションなしで実行した場合と、-pオプションを指定して実行した場合の結果を示しています。-pオプションを指定しない場合、mkdirはエラーを返しますが、-pオプションを指定することで深い階層のディレクトリを作成できます。
touchコマンド
Linuxでファイルを作成する方法はたくさんありますが、ここではtouchコマンドを使用します。
touchコマンド$ touch <新しいファイル名1> <新しいファイル名2> ...touchコマンドは中身のないファイルを作成します。複数ファイルを同時に作成したい場合には、スペースで区切って並べます。
本来touchコマンドはファイルのタイムスタンプ(日時)を更新するためのコマンドです。しかし、対象のファイルが存在しない場合には、新しくファイルを作成するという動きをするため、単純に空のファイルを作成するためにも使用できます。
touchコマンドでのファイルの作成は、誤って既存のファイル名を指定しても、内容が上書きされたり、削除されないため安心です。rmとrmdirコマンド
rmコマンド
rmコマンドはファイルを削除するコマンドです。
rmコマンド$ rm [オプション] <削除するファイル名1> <削除するファイル名2> ...複数のファイルを削除したい場合は、touch同様、スペースで区切って並べます。
rmでディレクトリの削除
rmでディレクトリを削除するには再帰的にディレクトリツリーを削除する-rオプションを指定します。
このとき、削除対象のディレクトリ内のファイルやディレクトリもまとめて削除しますので注意が必要です。
※注意
rmコマンドを実行するとファイルは本当に削除されてしまうため実行前には必ず削除していいものかどうか確認しましょう。WinやMacのようなゴミ箱はありません。rmdirコマンド
rmと似たコマンドにrmdirというコマンドがあります。これは空のディレクトリを削除するコマンドです。
rmdirコマンド$ rmdir <ディレクトリ名>rmコマンドは中にファイルのあるディレクトリを削除しようとしてもエラーとなる点がrmコマンドとの大きな違いです。
.hiddenのような隠しファイルがディレクトリ内に残っている場合にもrmdirコマンドでの削除はエラーが返ってきます。
rmdirコマンドを使うと中にファイルが存在するディレクトリを誤って削除することを防げます。
catコマンド
catコマンドはファイルの中身を表示するコマンドです。
catコマンド$ cat [オプション] <ファイル名1> <ファイル名2> ...作成したばかりのnewfileには中身がないため、catを実行しても何も表示されませんが、中身のあるファイルを指定するとその内容を表示します。
複数のファイルを指定した場合、その中身を連結して(連続で)表示します。
行番号を表示する
catコマンドでよく使用されるオプションに -n があります。これは行番号をつけて内容を表示するオプションです。
ファイルを指定しない場合
catコマンドでファイルを指定しない場合は、キーボードからの入力を待機するようになります。
catコマンド(引数なし)$ cat #引数なしでコマンド実行 Hello #Helloと入力した Hello #Helloと表示される #Ctrl+dを入力(キーボード入力終了) $ #プロンプトが戻るcatだけでなく、多くのLinuxコマンドは入力ファイルを指定しない場合、キーボードからの入力を待機します。この利用方法については後の記事で紹介します。
lessコマンド
catコマンドは単にファイルの中身をそのまま表示するだけでした。そのため表示したい内容が多い場合には、1画面に収まりきらなくなります。このような長いファイルをみたい場合にはlessコマンドを使用します。
lessコマンド$ less [オプション] <ファイル名>lessコマンドはファイルの内容を1画面ごとに表示して、画面を上下にスクロールすることができます。
lessコマンドのスクロール操作
コマンド 内容 スペースキー、f、Ctrl+v 1画面下にスクロールする b、Meta+v 1画面上にスクロールする j、Ctrl+n、Enter 1行下にスクロールする k、Ctrl+p 1行上にスクロールする q lessコマンドを終了する ファイル内の検索
lessコマンドでは現在開いているファイルから文字列を検索することができます。
ファイルを表示中に「/」を入力すると、一番下の行が検索文字列の入力欄に変わります。
文字列を入力してEnterを叩くことで検索されます。lessコマンドの検索操作
コマンド 内容 /<文字列> 下方向に向かって検索する ?<文字列> 上方向に向かって検索する n 次の検索結果に移動する N 前の検索結果に移動する 下の図は、lessコマンドの検索機能でetcという文字列を検索しています。
cpコマンド
ファイルをコピーするためにはcpコマンドを使用します。
cpコマンド$ cp [オプション] <コピー元> ... <コピー先>下の図では、newfileをnewfile2としてコピーしています。
また、ファイルをディレクトリへコピーすることもできます。これはnewfileをdir1へコピーしています。
複数のファイルをディレクトリにコピーする場合は、コピー元のファイルをスペース区切りで並べて、最後の引数にコピー先のディレクトリを指定します。
コピーの際の上書き確認
cpコマンドはコピー先に同名のファイルが存在していたとしても、確認せずに上書きしてしまいます。
ここで-iオプションをつけるとコピー先のファイルが存在する場合に、上書きしても良いかを確認してくれます。[y/n]で回答しましょう。
ディレクトリのコピー
cpコマンドではディレクトリをコピーしようとするとエラーになります。
そのため、ディレクトリをコピーする場合は再帰的にコピーを実行する-rオプションを指定します。
このとき、コピー先のディレクトリが存在していない場合には、指定した名前でディレクトリをコピーします。
一方、コピー先のディレクトリが存在している場合には、コピー先にディレクトリを指定したと受け取られて、コピー元をコピー先のディレクトリにコピーします。
mvコマンド
ファイルやディレクトリを移動するにはmvコマンドを使用します。
mvコマンド$ mv [オプション] <移動元> ... <移動先><移動元><移動先>にファイルを指定した場合は、ファイル名の変更をしているのと同義になります。
cpとは異なり、移動元からファイルがなくなることに注意してください。
また、移動先に同名のファイルが存在する場合には、上書きされてしまう点にも注意してください。-iオプションを指定することで、cp同様、上書き前に確認メッセージを表示できます。lnコマンド
lnコマンドはリンクを貼るコマンドです。
lnコマンド$ ln [オプション] <リンク元ファイル名> <リンク名>リンクとは
Linuxのファイルシステムでは、ファイルに別名をつけることができます。この機能をリンクと呼びます。
リンクには「ハードリンク」「シンボリックリンク」の2種類があります。「ハードリンク」の使用は限定的で、「シンボリックリンク」が頻繁に使用されます。ハードリンクとは
ハードリンクの使用
中身がhelloと表示されるfile1のハードリンクfile2を作成しました。
その後$ cat file2を実行するとfile1と同じ内容が表示されていることがわかります。
意味合いとしては、file1、file2の両方とも、本物の名前と言えます。
ハードリンクの削除
ハードリンクをもつファイルの実態は、全てのハードリンクがなくなったときに削除されます。
先ほど作成したハードリンクfile2の元であったfile1を削除しましたが、file2は実体をもっていることが下の図からわかります。
シンボリックリンクとは
ハードリンクはディレクトリに対して作成できない、異なるディスク間を跨がることができないという制限があります。一方で、シンボリックリンクはこのような制限を受けないため、シンボリックリンクの方が頻繁に使用されます。
シンボリックリンクとは、リンク先のパス名が書かれた小さな特殊ファイルです。
ハードリンクとは異なり、リンク元のファイルが実体です。
シンボリックリンクの使用
シンボリックリンクを使用するにはlnコマンドに-sオプションを指定します。
helloと表示するfile1にシンボリックリンクfile2を作成しました。$ cat file2で表示されているのはfile1の内容(hello)です。ls -lで詳細情報を表示するとfile2->file1のように、どのファイルへパスを示しているかが確認できます。
シンボリックリンクの削除
シンボリックリンクはrmコマンドで削除することができます。
シンボリックリンクの実体である元ファイルを削除するとシンボリックリンクは残されますが、リンクが壊れた状態になります。
このときシンボリックリンクを開いても実体がないためエラーを返されます。
シェルの設定によっては赤い警告でリンクが壊れたことを教えてくれます。
リンクの利用方法
リンクには次のような使い道があります。参考までに。
長いパス名を省略する$ ln -s local/work/code/project/source source $ cd source参考資料
- 投稿日:2020-05-21T12:48:51+09:00
command memo
uptime
起動時間
uptime 12:43 up 97 days, 2:24, 1 user, load averages: 1.93 2.39 2.61
hey
簡易なベンチマークツール
Summary: Total: 0.5759 secs Slowest: 0.5758 secs Fastest: 0.5758 secs Average: 0.5758 secs Requests/sec: 1.7366 Response time histogram: 0.576 [1] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.576 [0] | 0.576 [0] | 0.576 [0] | 0.576 [0] | 0.576 [0] | 0.576 [0] | 0.576 [0] | 0.576 [0] | 0.576 [0] | 0.576 [0] | Latency distribution: 0% in 0.0000 secs 0% in 0.0000 secs 0% in 0.0000 secs 0% in 0.0000 secs 0% in 0.0000 secs 0% in 0.0000 secs 0% in 0.0000 secs Details (average, fastest, slowest): DNS+dialup: 0.0516 secs, 0.5758 secs, 0.5758 secs DNS-lookup: 0.0009 secs, 0.0009 secs, 0.0009 secs req write: 0.0001 secs, 0.0001 secs, 0.0001 secs resp wait: 0.4800 secs, 0.4800 secs, 0.4800 secs resp read: 0.0441 secs, 0.0441 secs, 0.0441 secs Status code distribution: [200] 1 responses
- 投稿日:2020-05-21T02:19:05+09:00
Android Smart Phoneをpythonを使ってWeb Serverにする。
Android Smart Phoneをpythonを使ってWeb Serverにする。
Pydroid 3 - IDE for Python 3を使ったけど手を火傷して使用中止!
UserLandをGoogle Playよりインストールする。
sshでログインする。Rloginを使っています。Port 2022です。
環境整備します。vim editorを使えるようにします。
sudo apt update sudo apt upgrade -y sudo apt install -y vim vim test.c #include <stdio.h> int main(){ printf("hello world\n"); } hirata@localhost:~$ cc test.c hirata@localhost:~$ ./a.out hello world hirata@localhost:~$hello worldが出ればOK!
pythonの導入と確認
sudo apt update sudo apt install python3 sudo apt install python3-pip hirata@localhost:~$ python3 Python 3.6.9 (default, Apr 18 2020, 01:56:04) [GCC 8.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>>bottoleの導入
sudo pip3 install bottleテストプログラムの作成
web.pyfrom bottle import route, run @route('/') def root(): str="" for i in range(10): str=str+"<h1>Hello %d</h1>"%i return str @route('/hello') def hello(): return "<h1>Hello World!</h1>" run(host='192.168.1.16', port=8080, debug=True)実行
Visual Studio 2019で作成されたテンプレートの実行
. |-- app.py |-- routes.py |-- static | |-- content | | |-- bootstrap-grid.css | | |-- bootstrap-grid.css.map | | |-- bootstrap-grid.min.css | | |-- bootstrap-grid.min.css.map | | |-- bootstrap-reboot.css | | |-- bootstrap-reboot.css.map | | |-- bootstrap-reboot.min.css | | |-- bootstrap-reboot.min.css.map | | |-- bootstrap.css | | |-- bootstrap.css.map | | |-- bootstrap.min.css | | |-- bootstrap.min.css.map | | |-- jumbotron.css | | `-- site.css | |-- fonts | | |-- glyphicons-halflings-regular.eot | | |-- glyphicons-halflings-regular.svg | | |-- glyphicons-halflings-regular.ttf | | `-- glyphicons-halflings-regular.woff | `-- scripts | |-- _references.js | |-- bootstrap.bundle.js | |-- bootstrap.bundle.js.map | |-- bootstrap.bundle.min.js | |-- bootstrap.bundle.min.js.map | |-- bootstrap.js | |-- bootstrap.js.map | |-- bootstrap.min.js | |-- bootstrap.min.js.map | |-- jquery-1.10.2.intellisense.js | |-- jquery-1.10.2.js | |-- jquery-1.10.2.min.js | |-- jquery-1.10.2.min.map | |-- jquery.validate-vsdoc.js | |-- jquery.validate.js | |-- jquery.validate.min.js | |-- jquery.validate.unobtrusive.js | |-- jquery.validate.unobtrusive.min.js | |-- modernizr-2.6.2.js | |-- respond.js | `-- respond.min.js `-- views |-- about.tpl |-- contact.tpl |-- index.tpl `-- layout.tplapp.py""" This script runs the application using a development server. """ import bottle import os import sys # routes contains the HTTP handlers for our server and must be imported. import routes if '--debug' in sys.argv[1:] or 'SERVER_DEBUG' in os.environ: # Debug mode will enable more verbose output in the console window. # It must be set at the beginning of the script. bottle.debug(True) def wsgi_app(): """Returns the application to make available through wfastcgi. This is used when the site is published to Microsoft Azure.""" return bottle.default_app() if __name__ == '__main__': PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static').replace('\\', '/') HOST = os.environ.get('SERVER_HOST', 'localhost') try: PORT = int(os.environ.get('SERVER_PORT', '5555')) except ValueError: PORT = 5555 @bottle.route('/static/<filepath:path>') def server_static(filepath): """Handler for static files, used with the development server. When running under a production server such as IIS or Apache, the server should be configured to serve the static files.""" return bottle.static_file(filepath, root=STATIC_ROOT) # Starts a local test server. HOST,PORT="192.168.1.16",8080 bottle.run(server='wsgiref', host=HOST, port=PORT)routes.py""" Routes and views for the bottle application. """ from bottle import route, view from datetime import datetime @route('/') @route('/home') @view('index') def home(): """Renders the home page.""" return dict( year=datetime.now().year ) @route('/contact') @view('contact') def contact(): """Renders the contact page.""" return dict( title='Contact', message='Your contact page.', year=datetime.now().year ) @route('/about') @view('about') def about(): """Renders the about page.""" return dict( title='About', message='Your application description page.', year=datetime.now().year )
- 投稿日:2020-05-21T01:23:12+09:00
自分用: ネットワークのメモ
はじめに
ネットワークは前にやったきりで時間も経ってるため、だいぶ忘れてしまいました.
久しぶりにネットワークの復習と追加学習をしました.
その内容をここにメモします.
間違ってたりアドバイスあったら優しく教えてくれると助かります〜TCP
L3までのおかげでパケットを相手に送信する事ができるようになったが、実際に届いたかどうかはわからない.
なので、相手はパケットが届いたら届いたよ!と、教えたりするルールを設けたのがTCP.(詳しくは省くパケットを送る時はPORT番号を指定する必要がある.
TCPの場合、相手からのパケットも受け取る必要があるので、依頼元も今回の通信で使うPORT番号を指定する.
送信元PORT番号は[動的・プライベート ポート番号 (49152–65535)]から選ばれる.
つまり、このout用のport番号を超えた65535-49152=16383を超える同時な外部へのTCPでの接続は工夫しないと、基本的にできない.
UDPの場合は、送信元PORTが必要ないので、この動的ポート番号枯渇による起きる制限はない.ARP
http://www5e.biglobe.ne.jp/aji/3min/26.html
ARPはL3のプロトコルで、ARP Requestをブロードキャストすることにより、ARP Requestに含まれている ARP Replyを頂ける.
ARP ReplyにリクエストされたMACアドレスが含まれた状態で届く.
これを利用することにより、ARP tableに宛先mac addressがない場合でもパケットを届けられるようになる.ARPのusecaseその4ぐらい
手動でnic設定したstatic ip addressで一度も外部通信していない場合、bridgeやRouterのARP tableにmac addressが記録されていない.
その様な状態の時に、Routerは受け取った宛先 IPのMac AddressをARPを使って調べる.firewall
firewallでよく80番ポートだけ開放するとかやります.
その場合、80番ポート以外のポートが記載されたパケットを全てロスする設定になっていると、動的ポート番号のパケットまで捨てられてしまいます.
そうした場合、TCPを利用したやりとりができなくなってしまいます.
なので、当たり前ですが、基本的にinとout用でセキュリティで考慮することや設定は変わります.
ちなみにUDPの場合は、response用のポートを動的ポート番号で確保する必要ないので、UDPリクエストしかしないと保証されているようなクライアントがいた場合、全てのportを閉じてもデータを外部に送れます.NIC
eh0はnic0枚目、eth1はnic1枚目って事
ethN == nicって認識で基本大丈夫
物理レイヤーにパケットを送る場合はethに送信パケットを投げて、ethがそれをethのpeerに対して送る. (nicは基本イーサネットケーブル等を通じて、bridgeやrouter等、対となるnicと繋がっている.その対のことをpeerと呼ぶ.Router作成の概念
http://redhatlinux.kt.fc2.com/cont/router.htm
このサイトが詳しい.
route -n
の見方がわからない場合、このサイトを見るといい.
https://xtech.nikkei.com/it/article/COLUMN/20080520/303086/
http://linux.kororo.jp/cont/intro/dgate.phpコンバージェンスとか一旦置いといた、一番シンプルなRouterはNICから受け取ったパケットを別のNICに飛ばす技術であるip forwardだけで実現が可能.
linuxでip forwardを有効化するには、/etc/sysctl.conf
にnet.ipv4.ip_forward=1
を追記し、ネットワークを再起動すると、ip forwardの機能が有効化される.ifconfig vs ip command
ifconfigはnet-toolsパッケージに含まれているコマンド.
その他にもよく使うroute, netstat, arpなどもnet-toolsパッケージに入っているコマンド.
net-toolsパッケージは現在非推奨になっている.仮想bridgeの作り方
bridgeは以下のいずれからでも作成できる
- bridge-utils
- iproute2
- netctl
- systemd-networkd
- NetworkManager
bridgeにはeth0等の実デバイスとveth等の仮想デバイスを接続することができます
仮想networkの作り方
仮想nicを作りまくって、仮想bridgeに繋げば、仮想プライベートネットワークは作れる.
しかし、このままだとプライベートネットワークがインターネットとやりとりできない.
直接eth0と繋ぐと、今度はeth0が専有されて、プライベートネットワークに所属していない奴らがインターネットに接続できなくなる.
なので、iptablesを使い、ipマスカレードする事によって、できる.
なので、docker等のbridgeのipマスカレードの設定を消すと、完全にネットワークから切り離せる.ipマスカレード(NAPT
iptablesを使う事により、ipマスカレードを使える.
ipマスカレードを使うと、NAPTの機能はもちろん、port forwardや、securityとかも行える.port forward
https://qiita.com/Ayaka14/items/449e2236af4b8c2beb81
こんな感じ
iptablesでもできる
特定のportに届いたパケットを特定のip addressのportに転送できる.
L2のproxyとして使える.
また、ネットワークセグメント同士を繋ぐのにも使える.
ネットワークセグメント同士を繋げば、VXLANが構築できる.VXLAN
https://tech.uzabase.com/entry/2017/08/23/175813
このサイトが詳しい.冗長化
基本的に対障害の為、単一のマイクロサービスを複数ホストに配置したいので、1マイクロサービスは複数ネットワークセグメント上に展開する.
VXLANの感想
結局はroutingの設定って感じがした.
routingの特定項目の設定とかにport forwardとか色んな特別な名前をつけてる感じ.参考文献
- 3分間ネットワーキング
- IPフォワード
- IPルーティング
- 【図解】初心者にも分かる PPP の仕組み, フォーマット
- Linuxルーターから、PPPoEによるインターネット接続を行う
- チュートリアル:WAN設定:PPPoEを使用したWAN-IPアドレス取得の設定
- スーパーネット化
- ネットワーク ゲームにおけるTCPとUDPの使い分け
- DHCPとは
- VXLANとは
- Docker/Kubernetesを扱う上で必要なネットワークの基礎知識(その1)
- Docker/Kubernetesを扱う上で必要なネットワークの基礎知識(その2)
- Dockerのネットワークの仕組み
- TCPやUDPにおけるポート番号の一覧
- TCP ソケットバッファーを調整する
- https://qiita.com/zembutsu/items/9e9d80e05e36e882caaa
- Linuxマシンをルータにする方法
- 第13回 IPとルーティング
- デフォルトゲートウェイの設定 - コロのLinuxサーバー構築
- マルチホストでのDocker Container間通信 第1回: Dockerネットワークの基礎
- マルチホストでのDocker Container間通信 第2回 Port Forwarding と Overlay Network
- マルチホストでのDocker Container間通信 第3回: Kubernetesのネットワーク(CNI, kube-proxy, kube-dns)
- iproute2
- iproute2 wiki
- [netns] 秒速でネットワーク作成 [veth peer]
- LinuxのNetns/veth/Bridge/NATで仮想ネットワーク構築
- ネットワークブリッジ
- カテゴリ:ネットワーク
- 投稿日:2020-05-21T00:52:32+09:00
CentOS7のNW設定
はじめに
CentOS7のネットワーク設定についてメモ
ネットワークの設定
NetworkManagerサービスによってネットワーク設定を管理
- NICを表すデバイス
- 接続(デバイスに適用する設定)
デバイスに接続(設定)を紐付ける
定義済みのデバイスの確認
CONNECTIONが接続# nmcli d DEVICE TYPE STATE CONNECTION enp0s25 ethernet 接続済み enp0s25 lo loopback 管理無し --定義済みの接続の確認
# nmcli c NAME UUID TYPE DEVICE enp0s25 173098fd-54de-48b1-95a1-ceaa687089ab ethernet enp0s25新たな接続の定義
- 新しく接続したNICに対して新規の接続を紐付ける
- nmcli -d でデバイスはあるが、接続がない状態
nmcliとnmtuiで接続を作成して、デバイスを紐付ける
nmtuiはGUIで設定できるVLANデバイスの作成
VLAN77を作成
# nmcli c add type vlan ifname vlan77 con-name vlan-vlan77 dev enp0s25 id 77 接続 'vlan-vlan77' (1092e677-f16b-4a35-8839-19739d20a011) が正常に追加されました。1 VLAN=yes 2 TYPE=Vlan 3 PHYSDEV=enp0s25 4 VLAN_ID=77 5 REORDER_HDR=yes 6 GVRP=no 7 MVRP=no 8 PROXY_METHOD=none 9 BROWSER_ONLY=no 10 BOOTPROTO=dhcp 11 DEFROUTE=yes 12 IPV4_FAILURE_FATAL=no 13 IPV6INIT=yes 14 IPV6_AUTOCONF=yes 15 IPV6_DEFROUTE=yes 16 IPV6_FAILURE_FATAL=no 17 IPV6_ADDR_GEN_MODE=stable-privacy 18 NAME=vlan-vlan77 19 UUID=1092e677-f16b-4a35-8839-19739d20a011 20 DEVICE=vlan77 21 ONBOOT=yes上にIPアドレスを設定する
vlanデバイスの稼働確認
cat /proc/net/vlan/config VLAN Dev name | VLAN ID Name-Type: VLAN_NAME_TYPE_RAW_PLUS詳細
# cat /proc/net/vlan/vlan77 vlan77 VID: 77 REORDER_HDR: 1 dev->priv_flags: 1 total frames received 0 total bytes received 0 Broadcast/Multicast Rcvd 0 total frames transmitted 13 total bytes transmitted 1022 Device: enp0s25 INGRESS priority mappings: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 EGRESS priority mappings: