Linuxの最近のブログ記事

Linux memo 2023/12/30 glibc errno

Pofixではerrnoはthread safeとされていて、Linux(というかglibc)もthread safeだが、世の中にはそうでないシステムもあるらしく、そのせいでerrnoを使おうとすると「thread safeかどうか確認しろ」と無慈悲な指摘をするヘンテコな解析システムがあり、そいつを分からせてやるために無駄な調査を行うハメになった。

glibcのこのへんを見ると良い。
/csu/errno.c
/csu/errno-loc.c
/stdlib/errno.h

glibcがthread localに対応したのは下記かららしい。裏付けできなかったがおそらくこのタイミングでerrnoも対応したと思われる。
glibc-2.3 (2002-10-02) thread local
https://sourceware.org/legacy-ml/libc-alpha/2002-10/msg00048.html

Linuxがいわゆる昔のLinuxThreadsからネイティブスレッド(NPTL)に変更されたのはLinux-2.6.0からで、Linux-2.6.0は 18 December, 2003 にリリースされている。
https://kernelnewbies.org/LinuxVersions

errnoをgdb上から確認するために__errno_location()を直接呼ぶ方法も参考に。

Linux memo 2023/08/12 gdb,C++あたり

● gdb上でerrnoを表示する方法
(gdb) print *((int*(*)())__errno_location)()
(ただしglibc限定)
関数ポインタのキャストの型なにもわからない

● gdb中にシグナル受けて止まってうぜぇ
define nosignals
handle SIGPIPE noprint
handle SIGPIPE nostop
end
使いたいときほど設定忘れててすぐに使えずに困ることがあまりに多すぎたのでメモっとく

● ときどきSIGSEGVするプログラムをgdbで捕まえたい
define sigsegvrun
nosignals
break _exit
commands
run
end
end
時々**するプログラムを起こるまで繰り返し実行する用途に応用は利くと思う。

● debug情報が別ファイルになってる場合のgdbの設定方法
$ objcopy --add-gnu-debuglink=test.debug test
で、testというファイルにtest.debugを見に行けという情報を .gnu_debuglinkセクションに記録する
(gdb) set debug-file-directory ./debug
さらに別ディレクトリ(./debug/)にdebug情報入りelfファイルがある場合の設定方法
安定のmasamiさんブログからのコピペですすみません、、
elfファイルのdebugセクション分割とgdbの分割されたデバッグ情報のサポート機能めも
https://kernhack.hatenablog.com/entry/2016/07/18/161802

● Effective Morden C++ 項目7の補足
Effective Morden C++ 項目7「オブジェクト作成時の () と {} の違い」
には、ctorを呼ぶときは () ではなくて {} のほうがよいとしつつ、それが通用しない例をつあげている
- A) auto型変数で受ける場合
- B) initializer_listを引数に取るctorを持つclassの場合
B)の代表例として std::vector<>を提示している。

が、本に記載のない例として std::string(size_type, charT) もある。
- std::string('a', 6); // "aaaaaa" size==6
- std::string{'a', 6}; // {0x61, 0x06} size==2
参考:basic_string::コンストラクタ - cpprefjp C++日本語リファレンス

ちなみに英語でのカッコはこう呼ぶらしい
- () parentheses , round
- {} braces , curly
- [] brackets , square

Amazonアフィリンク

Linux上でのPCM音の入出力の標準となっているALSAについての入門書。音をデジタルデータとして扱うための導入、ALSAの役割とその基本的なAPIについて、ALSAを使ったサンプルプログラミングの解説、という構成になっている。

プログラミングというタイトルになってはいるものの、音をハードウェアから出力する部分を扱うため、比較的低レイヤーなプログラムの話になるし、同時に音をどのような形でデジタル表現しているかについての知識を要する内容になっている。たしかに入門書的な説明の本とはいえ、このへんの分野のことを学ぶんだという心構えは最低限必要かと思う。

プログラミングという触れ込みの本ではあるが、サンプルコードを見る限り、著者はどうもコーディングに慣れていないように見受ける。分野が分野なだけに、信号処理やリアルタイム処理やDSPといったハードよりの分野から流れてきたのかなと推測される。サンプルプログラムは、処理のフローを理解するのにはよいが、細かなコーディングの手癖はマネしない方がよい。

ハイレゾやらUSB Audio Device Classやらの話が登場するが、ハイレゾは本書ではほとんど関係ないし(ビットレート計算くらい)、また現代ではalsaがUSB限定というわけでもないので、このへんは差し引いて読んだほうがよい。

入門書にケチを付けても仕方ないのだけど、実践的な内容にまでは触れられていない。いつでもどこからでもデータを拾い放題な音声ファイルをALSAのクロック任せで出力すれば良いケースは一番シンプルな例で、現実は、音声ってストリームなリアルタイムのデータなので、アンダーラン・オーバーランやレイテンシやASRC(asynchronous sample rate convert)なんかを気にしないといけないのだけど、さすがにそういう内容を求めるのは酷か?とはいえ、P79のNoteにあるniceで優先度をあげようの部分なんか、ごまかすにしてももう少し書きようがあるだろうにと思ってしまう。ここはSCHED_FIFOのキーワードくらいは記載すべき。

と酷評気味に書いてしまったが、ALSAをていねいに解説したものなんて、書籍でもネット上の記事でも皆無に近いので、そういう意味では非常に貴重な本となっている。逆に、ALSAなんて公式ドキュメント読めばいいだろ(当然英語)、というくらいの心構えがある人はやっぱりあえて読まなくても良いとなってしまうか。

Linux memo 2022/01/16 locale編

● ネタ
Q. 2台あるLinuxマシンでのdateコマンドの実行結果のformatが異なる
A. 結局わからんかった

● LC_TIME
dateコマンド(coreutils)は出力フォーマットを指定することができるが、指定しなかった場合、環境変数LC_TIMEにあるlocaleに従ったフォーマットになる。たいていは "ja_JP.UTF-8" などの文字列が入っている。dateコマンドはnl_langinfo()関数を使いlocaleからフォーマット文字列を持ってきて使う。取れなかった場合"%a %b %e %H:%M:%S %Z %Y"を指定したものとして扱われる。(CentOSなどでは/etc/locale.confも使われる?)

● ssh時の環境変数
sshコマンド(OpenSSH)でリモートにログインするとき、通常はlocale関連の環境変数をローカルからリモートに引き継ぐようになっている。これは /etc/ssh/ssh_config にある「SendEnv LANG LC_*」の設定によるもの。これにより「どこからログインしたか」でdateの出力フォーマットが変わることになる。「こう設定しているはず」と思い込みをせずにそのshellごとに環境変数を確認しよう。

● locale
localeはi18nからlocaledefで作られるDBを引っ張ってくることで個別の情報を引っ張ってくる。Ubuntu-20.04の場合、/usr/share/i18n/locales/en_CA にある「date_fmt "%a %d %b %Y %r %Z"」からDBが作られている模様。DBは/usr/lib/locale以下に配置されている。

● TZ
dateコマンドはデフォルトではローカルタイムを表示するが、ローカルタイムとは環境変数TZもしくは/etc/localtimeで指定されたTZデータベースのものとなる。日本だとGMT+9すればよいからあまり意識しないが、サマータイム補正しないといけない国も多いため、サマータイム情報も入ったTZデータベースが必要となる。ちなみに日本でも1948年から1951年にサマータイムが導入されていたため「存在しないローカル時刻」でたまにハマる人がいる。

● 敗因
localeがミスマッチなしに機能している間はいいんだけど、aliasになっていたり指定したlocaleが見つからなかったり環境変数がなかった場合に、C.UTF-8を見に行くのか/etc/locale.confを使うのかnl_langinfo()ライブラリに組み込まれたデフォルトが使われるのかdateプログラムに組み込まれたデフォルトを使うのか、このへんがわからんかった。

● 少しだけ気になったところ
localeのLC_MEASUREMENTには、1(Metric)か2(US customary measurements)を指定できるらしいが、en_GBの場合は1になっており、「イギリスってメートル法に変わったんだったっけ?」とかムダに調べてしまった。移行しようとしているが慣習的にまだまだ浸透していない状態らしい(2021年の情報)。英語でメートル法で数字区切りが,小数点が.、な地域を選ぶとすると、オーストラリア・ニュージーランド・アイルランド・カナダ、あたりとなる。日付フォーマットだけは日本と同じ形式なとこが少なすぎてどうにもならん。

● 所感
Linuxをインストールするときは言語はもう英語にしているけど、localeだけは気になり(特に日付)、en_USではなくen_CAに設定していたんだけど、en_CAのlocaleなんてわざわざインストールしていない環境も多く、上記のようにハマることになってしまった。カスタマイズできる機能を提供してしまったがために逆にハマることになってしまっている気がする。

Linux memo 2021/09/17

● 補助グループID
補助グループID(supplementary group ID)は、(ユーザではない)プロセスがGIDとは別に持つグループIDの集合。setgroups(2)で設定でき、getgroups(2)で確認できる。ただしsetgroups()は特権(CAP_SETGID)が必要。
特権がないと設定できないので、通常はログイン処理の一貫で設定する。su(1)とかsshdとかがやっている。
setuid(2)やseteuid(2)などと似たような概念が必要になるが、suidのような特権を取り戻すのに近い処理はないので、そこまで複雑ではない。
補助グループIDは、プロセスの持つgidやegidとは別ものなので、setuidgidコマンド(busybox?)では設定されない。つまり、setuid(2), getgid(2)しただけでは補助グループIDは設定されない。「setuigid 1000 /usr/bin/id」 と 「su $(id -un 1000) -c "/usr/bin/id"」 とを比べてみるとよい。

● limitの設定方法
Linuxのlimit設定を変更した場合、setrlimit(2)を呼ぶかbash builtinのulimitを使うかというのが一般的にはなるが、util-linuxにあるprlimit(3)を使う方法もある。limit設定変更をしてそのままコマンド実行できるので、oneshotな実行をやりやすい。
$ prlimit --msgqueue=unlimited su $(id -un 1000) -c "./mqueue_test_prog"
なお確認するだけなら、getrlimit(2)やbuiltin ulimitを使う他に、/proc/self/limitを見る方法でもよい。
似たようなプログラムに setpriv(3)がある。uid,gid系の各種を設定して実行できる、らしい。

Linux memo 2021/01/09(Fri) ネットワーク雑多編

● TCPが遅延する話
TCPではいわゆるショートパット問題による輻輳を防ぐためのNagleアルゴリズム(RFC 896)がある。が、適当にTCP送受信してしまうとこれが遅延悪化を起こしてしまうことがある。例えば下記の例など。
俺の MQTTブローカー がこんなに遅いわけがない - Qiita
https://qiita.com/ryskiwt/items/551f5ad60d8c4cd14588
理由は、Nagleアルゴリズムとdelayed acknowledgmentとの相性が最悪だから。詳細はこのへんに詳しい。
Nagleアルゴリズムと遅延ACK - それが僕には楽しかったんです。
https://rabbitfoot141.hatenablog.com/entry/2018/11/18/003606

● Nagleアルゴリズムの無効化
setsockopt()でTCP_NODELAYを有効にするとNagleアルゴリズムを無効にできる。無効にするとショートパケット問題が生じるが、これはアプリケーションプロトコルレベルで対処したほうが手っ取り早い。具体的にはwrite()やwritev()システムコールで一度にたくさん送信するようにすればよい。
ググると「/proc/sys/net/ipv4/tcp_low_latency でグローバルに設定できる」と記したページがいくつか見つかるが、man 7 tcpにある通り、Linux-4.14からこのパラメータは何の意味も持たなくなっている(Linuxのソースコードも確認済み)

● delayed acknowledgmentの無効化
setsockopt()でTCP_QUICKACKを有効にするとdelayed acknowledgmentを無効にできる。ただし、無効にした場合、ACKと応答パケットを同時に送ったり、受信ウィンドウを効率よく使ったりすることができなくなる。結局これも、アプリケーションプロトコルレベルで応答を必要とするケースを減らしたり、スループットを求めるコネクションは別ソケットにする、などの対策が必要になる。

● 遅延量を調整できないの?
Nagleアルゴリズムはそもそも遅延する時間という概念を持っていない。
networking - How to set nagle timeout in linux kernel? - Server Fault
https://serverfault.com/questions/836675/how-to-set-nagle-timeout-in-linux-kernel
delayed acknowledgmentの遅延時間はLinx kernelが動的に決める。linux/include/net/tcp.hの「TCP_DELACK_MAX」「TCP_DELACK_MIN」がそれに当たる。40msecから200msecでスケールする(今どきのcpu archだと HZ はほぼ100以上のため)

#define TCP_DELACK_MAX ((unsigned)(HZ/5)) /* maximal time to delay before sending an ACK */
#if HZ >= 100
#define TCP_DELACK_MIN ((unsigned)(HZ/25)) /* minimal time to delay before sending an ACK */
#define TCP_ATO_MIN ((unsigned)(HZ/25))
#else
#define TCP_DELACK_MIN 4U
#define TCP_ATO_MIN 4U
#endif
コードの方を見た感じ、スケールのさせ方にもいろいろ手が入っているようで、おいそれと簡単に変更できる実装にはなっていない。非常によくわかっている場合を除いてパラメータを変更するのはおすすめできない。

● 他のアプローチ
逆の、積極的に送信を遅延させるTCP_CORK(setsockopt()で設定)というオプションがある。TCP_NODELAYを有効にしたままTCP_CORKのON,OFFを切り替えることで、TCPを実際に送信するタイミングを調整することができる。もちろんMSSも意識しないといけない。ので、結局は、TCP_CORKなんて使わずに、ユーザランドでバッファリングしてwrite()システムコールで一度にたくさん書いたほうが手っ取り早いのかもしれない。

● TCPのタイムアウト
「SO_SNDTIMEO, SO_RCVTIMEOが使える」と書いたページも見つかるが、Linuxのコードを読む限り、これらはsocket全般に広く効くものの、ことTCPに関してはこれらは使われないように読めた。TCPは代わりにTCP_USER_TIMEOUTで設定するというように見える。でもごめんちょっと自信ない、誰か本当のとこ教えて。

● tcp keep alive
再送やらタイムアウトやらヘタに頑張ってほしくないと思いTCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVLを設定する例もたくさん見られる。が、やっぱりワナがあるようで、設定しといたほうがいいものの、過信はしないほうが良さげ。
TCPとタイムアウトと私 - Cybozu Inside Out | サイボウズエンジニアのブログ
https://blog.cybozu.io/entry/2015/11/26/170019
結局、アプリケーションプロトコルレベルでも検知して後始末する系をケアせざるを得ないようだ。

● ApacheのTCP_NODELAYの状況
Nagle algorythem / TCP_NODELAY をまとめる - Qiita
https://qiita.com/uturned0/items/3ab037d4d2d0500586f5
ではApacheがNagleアルゴリズムをどうしているのかわからないと記載されているが、コード見た感じ、問答無用でAPR_TCP_NODELAYを設定しているようですね。

● nginxのパフォーマンス
Apacheに比べて静的コンテツの配信に強いとされるnginx、その理由はApacheがpreforkなのに対してnginxはイベント駆動だ、とか書かれたページがいくつか見つかるものの、どうもそれだけじゃイマイチ納得できなかった。REUSEPORTとかが効いてんのかなと持って調べてみると、その程度の話ではなく、もはやcontext switchやCPU cache lineのレベルで性能差が出ているという話の模様。そのレベルまで性能引き出せているなら、確かに、無駄にプロセスやスレッドを増やしたりせず、CPUコア数に応じただけの数のworkerをぶん回らせた方が早そう。でもそれ、ネットワークやディスクがボトルネックじゃないという前提も必要よね。このへんに詳しかった。
linux - Is Nginx's approach to CPUs scalability (per process epoll event queue) optimal? - Stack Overflow
https://stackoverflow.com/questions/62234057/is-nginxs-approach-to-cpus-scalability-per-process-epoll-event-queue-optimal
Why does one NGINX worker take all the load?
https://blog.cloudflare.com/the-sad-state-of-linux-socket-balancing/

● その他(過去の記事)
Linux memo 2019/11/22
https://www.rarul.com/mt/log/2019/11/linux-memo-2019-8.html
TIME_WAIT関連のメモ
https://www.rarul.com/mt/log/2018/01/time-wait.html

● その他(ネットワークですらない雑記)
LD_BIND_NOWという環境変数が使える。man ld.so(8)とか、見たことないパラメータがいっぱいあるな...このうちどれが実用的なやつなのかも正直よくわからん。

Linux memo 2021/01/03 CentOS Stream 8 編

● 前置き
長い間塩漬け運用していたCentOS6がEOFになっちゃったので移行することにした。CentOS 8はプロジェクトを中止する予定だし、別のRHELクローン立ち上げはまだまだ時間かかるだろうし、ということで素直にCentOS Stream 8を移行先に選んだ。

● dnf
yum から dnf に変わった
オプション類がだいたい一緒なのでノリでそのまま使える。

● selinux
どうして人はみなselinuxを無効にしてしまうのだろうか(自戒を込めて)
/etc/selinux/config
SELINUX=disabled

● 公開鍵の暗号強度の確認
ssh-keygen -l -f ~/.ssh/authorized_keys
昔作ったのが RSA 1536 だったので、作り直すことにした。オプションなしに作ったら RSA 3072 になった
ちなみに、ssh-keygenで作ったときのファイルの id_rsaが秘密鍵、id_rsa.pubが公開鍵、「わからないから両方送ります」とかしないように

● firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
firewall-cmd --permanent --new-zone=rarullocal
firewall-cmd --permanent --zone=rarullocal --set-target=ACCEPT
firewall-cmd --permanent --zone=rarullocal --add-source=192.168.0.0/16
firewall-cmd --permanent --zone=rarullocal --add-service=samba
firewall-cmd --reload
AllowZoneDriftingがどうとか怒られるので、マルチゾーンにならないようにした上で、
/etc/firewalld/firewalld.conf
AllowZoneDrifting=no

● sshd
/etc/ssh/sshd_config
Port [NewPort]
PasswordAuthentication no
パブリックサーバだと最近はつつくやつが非常に多いので、ポート番号変えた上でパスワード認証なしくらいにしとかないと怖い。

● dnsmasq
/etc/dnsmasq.conf
domain-needed
bogus-priv
local=/www.rarul.com/
/etc/hosts
192.168.123.234 www.rarul.com

● chronyd
#pool 2.centos.pool.ntp.org iburst
server YOURSERVER iburst
allow 192.168.0.0/16
port 123
(port 123 は、ntpdを内部公開したい場合に)

● Apache(httpd.conf)
あんま晒したくないので部分的に、、
 ※ 2021/02/02訂正、.gitはディレクトリなので、FilesでマッチさせるのではなくてFilesDirectorymatchでマッチさせる。
/etc/http/conf/httpd.conf
<FilesDirectorymatch "^/.*/\.git/">
Require all denied
<Files/Directorymatch>
#AddDefaultCharset UTF-8
ExpiresActive on
ExpiresDefault "access plus 3 minutes"
ExpiresByType image/gif "access plus 1 days"
ExpiresByType image/png "access plus 1 days"
ExpiresByType image/jpg "access plus 1 days"
ExpiresByType image/jpeg "access plus 1 days"
ExpiresByType image/ico "access plus 1 days"
ExpiresByType image/x-icon "access plus 1 days"
ExpiresByType image/vnd.microsoft.icon "access plus 1 days"
ExpiresByType text/css "access plus 1 days"
ExpiresByType text/javascript "access plus 1 days"
ExpiresByType application/x-javascript "access plus 1 days"
ExpiresByType application/javascript "access plus 1 days"
ExpiresByType audio/mp3 "access plus 1 days"
AddOutputFilterByType DEFLATE text/plain text/html text/css
AddOutputFilterByType DEFLATE text/xml application/xml application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml application/atom+xml application/rdf+xml
AddOutputFilterByType DEFLATE text/javascript application/x-javascript application/javascript

/etc/httpd/conf.d/ssl.conf
の SSLCertificateFile, SSLCertificateKeyFile を Let's Encryptに合わせて変更。
warningログがうざかったので使う予定ないモジュールをコメントアウト
/etc/httpd/conf.modules.d/00-proxy.conf
#LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so

● .htaccess
order deny,allowとかSatisfy AnyとかがApache-2.4から使えなくなったんでその置き換えで。
AuthUserFile /home/rarul/.htdigest
AuthGroupFile /dev/null
AuthName "for members only"
AuthType Digest
<RequireAny>
Require all denied
Require user [USERNAME]
Require ip 192.168. 127.0.0.1
</RequireAny>
Digest認証はmd5なのでそれほど強度強くない。HTTPS化が大前提として、本気で認証したいなら...なにがいいんだろ。HTTPSなら他のid/pass方式でも大差ない気がしてきた。

● MariaDB
vi /etc/my.cnf.d/client.cnf
[client-mariadb]
default-character-set = utf8mb4
データベース作るときに明示的にデフォルト文字コードを設定
create database YOURDB character set utf8mb4;
それでも、phpからアクセスするときに SET NAMES utf8mb4 しないと化けることがあったけど、正直良くわからんし、SET NAMES utf8mb4 すればよいから、もう原因追求諦めた。
utf8mb4じゃない文字コードで作ってしまったDBは、潔くutf8mb4じゃない文字コードのまま運用したほうが無難げ。(特にutf8とutf8mb4との違いには要注意) 文字コードをutf8mb4に変換したい場合は、移行作業とは別の機会を構えたほうがよいと思う。これでようやくSET NAMES binaryを卒業できた。
あとマジメにチューニングしてないけどRAM余り気味のサーバなので適当に盛っといた。
/etc/my.cnf.d/mariadb-server.cnf
[mysqld]
hread_cache_size=16
query_cache_size=128M
sort_buffer_size=8M
join_buffer_size=64M
read_buffer_size=1M
read_rnd_buffer_size=2M
myisam_max_sort_file_size=64M

● PHP
ereg -> preg_match
mysql_connect -> mysqli_connect
mysql_query -> mysqli_query
mysql_real_escape_string -> mysqli_real_escape_string
mysql_fetch_assoc -> mysqli_fetch_assoc
mysql_free_result -> mysqli_free_result
mysql_close -> mysqli_close
他にもあった気がするけど、まぁ似たようなノリでなんとかなるでしょ。

● Let's Encrypt
/etc/letsencrypt/を移行しておいた上で、certbot-autoをダウンロードして実行するだけ、あとは全部勝手にやってくれる。すごい。

● その他(省略したとこも含めて)
centos8stream.txtを見てね >未来のらるるさんへ

このアーカイブについて

このページには、過去に書かれたブログ記事のうちLinuxカテゴリに属しているものが含まれています。

次のカテゴリはPCハードウェアです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

ウェブページ

Powered by Movable Type 7.9.0