- 投稿日:2020-06-28T18:06:08+09:00
LinuxのOpenVPNですべてのトラフィックをVPN経由にする方法
.ovpnファイルに下記の一行を追加して接続する。
redirect-gateway def1
- 投稿日:2020-06-28T16:08:13+09:00
ルートディレクトリ(/)とホームディレクトリ(~)のちゃんとした理解
ものすごい細かいことだけど、パスの指定方法での
~
(チルダ)と/
(スラッシュ)の理解が曖昧で気持ち悪い思いをしたのでメモ。
/
: ルートディレクトリ
~
:今のユーザーのホームディレクトリ
~taro
: taroというユーザーのホームディレクトリスラッシュの意味合い
ルートディレクトリの
/
と、各ファイルやディレクトリの前につく/
は意味合いが違っている模様。
- 前者:ルートディレクトリそのもの
- 後者:ディレクトリを区切るもの
なので、一見ルートディレクトリのせいで「ディレクトリとは末尾にスラッシュが付いているもの」という勘違いを(少なくも筆者は)しちゃうが、
hogehoge/
がディレクトリなのではなくhogehoge
がディレクトリなのだ。ホームディレクトリを~/
だと思ってしまっている人は多いのではないか?~ユーザー名
また
~taro
でtaroさんのホームディレクトリを指定できるのは初耳で、結構ググったけどこれについて深く語っている記事は見当たらなかった。こういう指定の仕方があるんですね。teratailで教えてもらった?
https://teratail.com/questions/273447Node.jsのSass特有の書き方
今回がそもそも、RailsアプリでBootstrapを導入しようとして疑問にわいたことだったのだが、Node.jsのSass特有の書き方として、以下のような相対パス?の書き方が使えるらしい。
@import '~bootstrap/scss/bootstrap';上記は
myapp/node_modules/bootstrap/dist/css/bootstrap.css
を指定できる。モジュールをユーザーに見立てているのかな?まとめ
こういうのって「そういうもの」と暗記する人が多いと思うんだけど、数学の公式と一緒で「なぜそうなるのか?」という部分を理解したほうが知識を応用できると思うんです。
今回のものを踏まえると、WebのURLで
https://example.jp
とhttps://example.jp/
のどっちを正規URLとすべきかという問題は、前者のほうが本来は正しいのではないかと考えちゃう。
- 投稿日:2020-06-28T03:52:58+09:00
Activiti 6 のインストール
試したのでメモ
前提
- JDK インストール済み
- Tomcat インストール済み
手順
あらかじめ Activiti 6 の WAR ファイルをサーバに配置しておく
# curl -LkvOf https://github.com/Activiti/Activiti/releases/download/activiti-6.0.0/activiti-6.0.0.zip
Activiti 6 実行用ユーザを作成する
# useradd activiti
Activiti 6 用のディレクトリを作成する
# mkdir /opt/activiti
Tomcat のディレクトリを作成したディレクトリ内に配置する
# mv /root/apache-tomcat-8.5.56 /opt/activiti/tomcat
デフォルトで配置されている Web アプリを
tomcat/webapps
から削除する# rm -rf /opt/activiti/tomcat/webapps/*
Activiti 6 の WAR ファイルを
tomcat/webapps
配下に配置する# cp /root/activiti-*.war /opt/activiti/tomcat/webapps/
tomcat/bin/setenv.sh
ファイルを作成する# vi /opt/activiti/tomcat/bin/setenv.sh
CATALINA_PID=$CATALINA_HOME/activiti.pid ### 以下は JDK 11 のときに記載 CATALINA_OPTS="--add-opens=java.base/java.lang=ALL-UNNAMED \ --add-opens=java.base/java.io=ALL-UNNAMED \ --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED" export CATALINA_OPTS所有者を変更する
# chown -R activiti: /opt/activiti
サービスファイルを作成する
[Unit] Description=Activiti Service [Service] Type=forking User=activiti PIDFile=/opt/activiti/tomcat/activiti.pid ExecStart=/opt/activiti/tomcat/bin/startup.sh ExecStop=/opt/activiti/tomcat/bin/shutdown.sh [Install] WantedBy=multi-user.target起動する
# systemctl daemon-reload && systemctl start actitivi
- 投稿日:2020-06-28T01:59:31+09:00
signal送信元を知る
はじめに
プロセス間の非同期通信としてよく使われるsignalですが、
送信元を知る必要があり方法を調べてみたので備忘メモとして残しておきます。試した環境は以下のとおりです。
$ lsb_release -d Description: Ubuntu 18.04.4 LTS $ uname -r 5.3.0-61-generic $ trace-cmd --version | grep version trace-cmd version 2.6.1 $ stap --version | head -1 Systemtap translator/driver (version 4.3/0.170, commit release-4.3-0-gc9c23c987d81)方法1. sigaction(2)で知る
signalを受け取るプロセスで送信元の情報を取得するアプローチです。
signalを受け取るプロセスを変更することができて、
かつプロセスでハンドリングできるsignalが調査対象の場合に使える方法です。
SIGKILLのようにプロセスでハンドリングできないsignalには使えません。sigaction(2)は、
sa_flags
にSA_SIGINFO
を指定することで、
シグナルハンドラでsignalに関する詳細な情報siginfo_t
を受け取ることができるようになります。
si_pid
で送信元のPIDを、si_uid
で送信元の実ユーザIDを知ることができます。#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> static int g_sig; static siginfo_t g_siginfo; static void my_sigaction (int sig, siginfo_t *info, void *ucontext) { g_sig = sig; // memcpy(3) is a async-signal-safe function // according to man signal-safety(7) memcpy (&g_siginfo, info, sizeof(g_siginfo)); } static char* code2str (int code) { switch (code) { case SI_USER: return "SI_USER"; case SI_KERNEL: return "SI_KERNEL"; case SI_QUEUE: return "SI_QUEUE"; case SI_TIMER: return "SI_TIMER"; case SI_MESGQ: return "SI_MESGQ"; case SI_ASYNCIO: return "SI_ASYNCIO"; case SI_SIGIO: return "SI_SIGIO"; case SI_TKILL: return "SI_TKILL"; default: return "unknown"; } } int main (void) { struct sigaction act; act.sa_flags = SA_SIGINFO; act.sa_sigaction = my_sigaction; int ret = sigaction(SIGTERM, &act, NULL); if (ret < 0) { perror ("sigaction"); exit (EXIT_FAILURE); } printf ("pid: %d\n", getpid()); sleep (10000); fprintf (stderr, "sig: %d, si_pid: %d, si_uid: %d, si_code: %s\n", g_sig, g_siginfo.si_pid, g_siginfo.si_uid, code2str(g_siginfo.si_code)); return 0; }方法2.trace-cmd (=ftrace)で知る
kernelは誰が誰にsignalを送ったか知っているので、kernelのイベントをトレースすることで調べるアプローチです。
kernelのイベントトレースには、ftraceを使います。ftraceで
signal_generate
のイベントをトレースすることで送信元を特定することができます。
debugfsからftraceを直接操作してもいいですが、ここではtrace-cmd
を使ってトレースする方法を紹介します。[トレース開始] $ sudo trace-cmd start -e signal_generate -f 'sig==9 && pid == 6985' [トレース終了] $ sudo trace-cmd stop [トレース結果の確認] $ sudo trace-cmd show # tracer: nop # # entries-in-buffer/entries-written: 1/1 #P:8 # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | test_sender-6993 [001] d... 1660.447368: signal_generate: sig=9 errno=0 code=0 comm=test_receiver pid=6985 grp=1 res=0
pid=6985
のプロセスにsig=9
を送ったのは、test_senderというPIDが6993のプロセスであることがわかります。ここで
signal_generate
イベントは大量に発生するので、上記のように-f
オプションを使い適切にフィルタをかけたほうが良いです。
上記では、signal番号とsignalを受け取るpidでフィルタしています。フィルタ関数で使えるfield名は、
trace-cmd list
コマンドで確認できます。$ trace-cmd list -F -e signal_generate system: signal name: signal_generate ID: 194 format: field:unsigned short common_type; offset:0; size:2; signed:0; field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1; signed:0; field:int common_pid; offset:4; size:4; signed:1; field:int sig; offset:8; size:4; signed:1; field:int errno; offset:12; size:4; signed:1; field:int code; offset:16; size:4; signed:1; field:char comm[16]; offset:20; size:16; signed:1; field:pid_t pid; offset:36; size:4; signed:1; field:int group; offset:40; size:4; signed:1; field:int result; offset:44; size:4; signed:1;方法3.systemtapで知る
方法2と同じく、kernelのイベントをトレースすることで調べるアプローチです。
kernelのイベントトレースにsystemtapを使います。下記のようにワンライナーでモニタできます。
$ stap -e 'probe signal.send { if (sig==9 && sig_pid==8722) printf("%s: %s(%d) -> %s(%d)\n", sig_name, execname(), pid(), pid_name, sig_pid) }' SIGKILL: test_sender(9191) -> test_receiver(8722)スクリプトにして、ついでに引数取れるようにすると以下のようになります。
(qiitaにsystemtapモードがないようなので、c言語モードにしています)signal_sender.stp#!/usr/bin/env stap probe signal.send { if (sig==strtol(@1,10) && sig_pid==strtol(@2,10)) printf("%s: %s(%d) -> %s(%d)\n", sig_name, execname(), pid(), pid_name, sig_pid) }systemtapはPCだとこのようにスマートにできるのですが、
組み込みだとコンパイル環境と実行環境が別になるため手順が少し煩雑になるのが欠点です。まとめ
他にもあると思いますが、選択肢として3つ紹介しました。
調べた中にはSELinuxのaudit.logを利用するなんて方法もありました(ご興味があればこちらをご覧ください)。
個人的には、使いやすさと環境のハードルのバランスがいいのは、ftrace(trace-cmd)かなと思ってます。
ちょっと力尽きてしまいましたが、eBPFでもできるでしょうからeBPF版もそのうち追記したいです。参考
Man page of SIGACTION
trace-cmd(1) - Linux man page
stap(1): systemtap script translator/driver - Linux man page
trace-cmdコマンドの使い方 - Qiita
プロセスへの SIGKILL の送信元を追跡する方法 - Red Hat Customer Portal
takeoverjp/test_signal: signal simple test program