UNIXやLinuxの最近のブログ記事

この年末に、某システムのデータの圧縮方式を LZH から ZIP に変更した。
ユーザーが複数の CSV ファイルをひとつのアーカイブにまとめアップロードしたものを、サーバ(CentOS)上で自動で展開(解凍)し諸々の処理をするシステムだ。

初版公開が 2005年(俺が独立した翌年に作ったシステムだ(笑))なので、当時の Windows のファイル圧縮方式としては LHA(LZH方式)が主流だった。いや、もう、ZIP形式が LZH形式を駆逐してしまう未来は見えていた頃だが、このシステムを使うユーザーの職場ではまだ LZH形式が主流だったのだ。

しかし、あれから 18年。ついにユーザーより「もう、ZIP形式に変更したい~!」という声が出てきた。そのため、解凍コマンドを lha から unzip に変更した際の苦労話は「unzip の日本語ファイル名問題、なんとか解決」というエントリーにもちょっと書いているので、興味がある人は御一読下さいませ(笑)

件のエントリーでは「展開後の日本語ファイル名を EUC-JP で出力する」苦労話をまとめているが、その後、展開したファイルを正しく読み込めないという不具合が発生した。
ログなどを見て、どうもダブルバイト文字を正しく読めていないようだということはわかった。古い Perl のプログラムなので EUC-JP で書かれており、読み込むファイルの中身も EUC-JP である前提で処理をしているようだ。

ユーザーがアップロードするファイルは、Windows で作られているので文字コードは Shift_JIS である。しかし、プログラム内で Shift_JIS を EUC-JP に変換している箇所が無い。なのに、なんで今まではファイルの中身がちゃんと読めてたの???(どこで文字コードが EUC-JP に変換されてるの???) 

まあ、このエントリーのタイトルに思いっきり「落ち」を書いてるけど、lha コマンドでファイルを解凍するときに同時に EUC 変換していたのだ。lha コマンドにはそういうオプションがある。

lhaコマンドの引数には「オプション」と「コマンド」というのがあり、-e と書けば「圧縮ファイルを展開する」というコマンドを設定したことになる。
そのコマンドの前に e と書けば「テキストファイルの文字コードを EUC と相互変換する」というオプションが設定されたことになり、ファイル展開時に自動的にテキストファイルの文字コードが EUC に変換されるのだ。

具体的には、

/usr/local/bin/lha e -e -i -w=./temp hogehoge.lzh

のようなコマンドを投げていた。「e -e」という部分がそうだ。

いやあ、ハマったわ・・・。まさか lha コマンドが EUC 変換までしているとは思いもしなかった・・・(^^;;;
俺が書いたプログラムだけど 18年も前のものなので記憶が・・・

結局、unzip による ZIP ファイルの解凍のあとに、ファイルの中身を EUC 変換する処理を追加して解決した。

昔の UNIX 及び UNIX ライクな OS の主流の文字コードは Shift_JIS ではなく、まだ Unicode も正式に実装されておらず、EUC-JP の一人勝ち状態だった。だから lha にも EUC 変換オプションなんかが実装されているんだろうなあ(笑)
随分前に作った Linux(CentOS)上で動くプログラム。
LZH ファイルを解凍し、そのファイルをほげほげするのだが、さすがにもう Windows 上で LZH ファイルを作るのもきつくなってきた・・・ということで ZIP ファイル対応を依頼されたのだが(例えば、7-Zip なんかでも LZH 形式には対応してないからな(^^;)・・・ハマった(^^;

yum で入れた unzip は -O オプション(アーカイブ内のファイル名のエンコードが指定できる)が使える(以前のバージョンではパッチを当てないと駄目だった)ので、例えば unzip -Ocp932 -l exsample.zip で、exsample.zip の中の「かわいい中年男性一覧.csv」みたいなファイル名は取ってこれるんだけど、これをディスク上に解凍するとファイル名が化けまくる・・・

ちなみに、プログラムは EUC-JP で書かれている。なにせ、もう、18年前に初版公開したプログラムだからな(笑)。

これ、lha コマンドは EUC-JP でファイル名を出力するパッチが当たっていたので問題なかったんだけど、unzip は「サーバの locale のエンコードでファイル名が作られる」ため、実行サーバの locale である UTF-8 のファイル名となる。

他のプログラムにも影響あるから、なんとか EUC-JP でファイル名を設定してほしいなあ。

しかし、unzip にそのようなオプションはない。結局、unzip を実行する前に、locale を EUC-JP にする形でなんとかなった。

(例)
export LC_CTYPE=ja_JP.eucJP; /usr/bin/unzip -OCP932 -d /tmp exsample.zip

このプログラムは実行後シェルを閉じるので、LC_CTYPE の設定を投げっぱなしだが、同一シェル内で他のコマンドなど実行するのなら、

export LC_CTYPE=ja_JP.UTF-8

で locale を元の UTF-8 に戻すこと。

20230529_gmo_con.jpg

昨日、GMOの VPS コンソール経由でサーバ設定を触る必要があったので、vi エディタでコンフィグファイル開いて編集して、「さて保存」と「:w」(コロン、ダブリュー)とコマンドを入れようとしたら・・・

「???入力できない???」

よく見てみると、設定部分でも「:(コロン)」を入れたつもりが「;(セミコロン)」になってる・・・
だからコマンド入力待ちにならないのか・・・

どうも、GMOの VPS コンソール経由でコロンが入力できないのは既知の問題のようだ。ググってみると「Shift + 11」と入力すれば「:.!」という三文字が表示されるので、後ろの二文字を BS で消してコロンだけにしてやればいいらしい。

・・・が、この時はググってる時間も環境もなかったので、一旦 Ctrl + Alt + Del 信号を送ってサーバを再起動し(VPS ポータル画面から再起動すると 15分くらい起動にかかるんだけど、Ctrl + Alt + Del で再起動すると 1~2分で再起動するよ)、バックアップしていたコンフィグファイルをコピーして対応した。

いや、この時点でも十分な設定ではないのだが、これで ssh 接続はできるようになるので、あとは putty から接続して再度設定ファイルを編集した。

まあ、今後はこれでなんとかなるんだけど、こんな変な動き、さっさとどうにかすればいいのに>>>GMO
CentOS 7 上で、Apache を 2.4.6 から 2.4.54 にバージョンアップしたら CGI が実行できなくなった。

一旦 2.4.6 をアンインストールして、iusレポジトリから yum で 2.4.54 をインストールしたんだが、CGI を実行すると Internal Server Error になる。

error_log には、

End of script output before headers: hogehoge.cgi

としか出てない「何が原因がわからないエラー」だ。「End of script output before headers」って、「Content-type: text/html;charset=UTF-8」のようなヘッダ部すら送られない、つまり「プログラムがまったく実行されていない」状態である。

まあ、こういう場合は suEXEC 関係だろうな・・・と思い、/var/log/secure を見てみると、

Jan  7 11:23:42 httpd suexec[15490]: command not in docroot (/home/www/htdocs/hogehoge.cgi)

って。やっぱり「docroot」関連か。

# /usr/sbin/suexec -V
 -D AP_DOC_ROOT="/var/www"
 -D AP_GID_MIN=100
 -D AP_HTTPD_USER="apache"
 -D AP_LOG_SYSLOG
 -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
 -D AP_UID_MIN=500
 -D AP_USERDIR_SUFFIX="public_html"

Document Root が /var/www になっている。
Apache 2.4.6 のときに Document Root を /home で作り直したのだが(DOcument Root が /home/www/htdocs なので)、2.4.54 にした際に suexec コマンドも作り直されてしまった。

suEXEC の設定は、コンフィグファイルのようなもので簡単に指定できない。
再コンパイルしてプログラムを作り直す必要があるのだ。(これがなかなか手間)

ただし、suEXEC 自体はなにかセキュリティ上の問題が出ているわけではないので、2.4.54 で作られる最新のものでなくても問題ないはずだ。
残念ながら、Web サーバ上の suexec は書き換えられてしまったが、予備機にまだ 2.4.6 のときのプログラムが残っている。
FTP で suexec コマンドを持ってきて置いてみた。

・・・が、

# suexec -V
-bash: /usr/sbin/suexec: Permission denied

実行権限エラーが・・・

error_log にも、

Permission denied: exec of '/usr/sbin/suexec' failed

と出ているので、オーナーと実行権限を直してみる。

# chown root:apache /usr/sbin/suexec
# chmod 510 /usr/sbin/suexec
# /usr/sbin/suexec -V
 -D AP_DOC_ROOT="/home"
 -D AP_GID_MIN=100
 -D AP_HTTPD_USER="apache"
 -D AP_LOG_SYSLOG
 -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
 -D AP_UID_MIN=500
 -D AP_USERDIR_SUFFIX="public_html"

実行できた。
ちゃんと suEXEC で実行される CGI のある Document Root が /home 以下になっている。ばっちり。

しかし、これで、error_log に Permission denied は出なくなったがやっぱり CGI は実行されない。

/var/log/secure には「failed to setgid」と。

Jan 09 22:00:50 httpd suexec[31741]: uid: (1001/hogeusr) gid: (1001/hogegrp) cmd: hogehoge.cgi
Jan 09 22:00:50 httpd suexec[31741]: failed to setgid (1001: hogehoge.cgi)

そうかそうか。結局、SUID 設定をしないとダメなのだな。

# chmod u+s /usr/sbin/suexec
# ls -la /usr/sbin/suexec
-r-s--x--- 1 root apache 15368 Apr  3  2020 /usr/sbin/suexec

これで、ばっちり CGI も suEXEC 有効で実行されるようになった。

今後は、Apacbe のバージョンアップをするときに suexec コマンドを別名で退避しておいて、Apache インストール後にもとに戻すようにしよう。
Raspberry Pi を監視カメラ装置として使おうと思うので、起動時は X Window System の GUI 環境ではなく、コンソールの CLI 環境で起動したい。

なんか、これもググってみると、raspi-config を起動してメニューから設定・・・という内容が多い。
これも、誰かが最初に作った説明ページを見て、真似て同じようなページを作る輩の仕業だな(笑)

GUI から CLI に切り替えるのに、いちいちメニュー画面なんか起動しなくていいよ。

raspi-config コマンドは nonint オプションをつけると Non-Interactive(ノンインタラクティブ)モードで実行されるので、こっちの方が簡単。

まず、現在の起動モードを確認。

root@camera1:~# raspi-config nonint get_boot_cli
1

結果が 1 のときは GUI、0 のときは CLI で起動する。
現在は 1 なので、X Window System が起動する。

CLI 起動に変更する。

root@camera1:~# raspi-config nonint do_boot_behaviour B1

で、起動モードを確認。

root@camera1:~# raspi-config nonint get_boot_cli
0

結果が 0 なので、今後は起動時に CLI モードで起動する。

あとは reboot してみて確認しよう。

いつも散々「UNIX系OS(Linux も含む)で設定変えるたびに reboot するやつ、めっちゃ格好悪い」て言うてますが、今回は「起動時の画面設定」だからね。再起動してみないと結果はわからない。

ちなみに、CLI から GUI に変えるときは、

root@camera1:~# raspi-config nonint do_boot_behaviour B3

である。
いや、ずっとサーバ管理をやってる人には常識だったんだろうけど・・・

最近の bind って(ver 9.8以降)、マスターサーバからコピーしてきたスレーブサーバの zone ファイルって raw 形式っていう、いわゆるバイナリデータになってるんだね。

いつもの調子で、

# cat chroot/var/named/slaves/exsample.com.zone

なんてやったら、画面がぐちゃぐちゃに乱れてビビったわ(笑)

named-compilezone というコマンドで、text 形式に変換して表示できるということなのでやってみた。

# named-compilezone -f raw -F text -o - exsample.com chroot/var/named/slaves/exsample.com.zone
zone exsample.com/IN: loaded serial 2021091501
exsample.com.               28800 IN SOA  serv1.exsample.com. root.serv1.exsample.com. 2021091502 21600 3600 604800 28800
<略>
OK

おお、ちゃんと表示された。

ちなみに、コマンド引数の意味は、

named‐compilezone -F text -f raw -o (出力ファイル名) (ゾーン名) (ゾーンファイル名)

である。

出力ファイル名を '-' とだけしておけば、標準出力に出力される。
ゾーン名は、そのゾーンファイルに設定されているドメイン名ね。
ゾーンファイル名については、「ファイル名だけでパスは必要ない」と説明しているサイトがあるが嘘です。ちゃんとパスまで指定しないとファイルが見つからなくて、

dns_master_load: file format mismatch
zone exsample.com/IN: loading from master file exsample.com.zone failed: not implemented
zone exsample.com/IN: not loaded due to errors.

みたいなエラーになるぞ。「file format mismatch」って出てるけど、ちゃんとスレーブの zone ファイルが見つけられてないだけだ。「chroot/var/named/slaves/exsample.com.zone」みたいにフルパスで指定すれば問題なく実行される。

あと、named.conf の options に「masterfile‐format text;」を追加すれば、バイナリではなくテキストで出力されるらしんだけど、うちの環境ではエラーが出て bind が起動しなかった。

まあ、別にバイナリでも named-compilezone コマンドで確認できるからいいけど。

AlmaLinux 8.4 は、CentOS 8 の互換 OS だ。
そのため、CentOS 8 と同じで、TCP Wrapper が廃止され、今までのように /etc/hosts.allow や /etc/hosts.deny で IP アドレスによるアクセス制限がかけられなくなった。ファイアウォール(firewalld)で制限をかけることになる。

CentOS 8 を触ったことがなかったもんで(最近設定したのも、サポートのことを考えて CentOS 7 だったからなあ)、/etc/hosts.allow を編集しようと思ったらなかったので驚いた。

まず、自宅 PC や既存サーバなど、恒常的に存在している機器はパーマネントルール(設定ファイルに書き込まれ、再起動時にも有効となるルール)を投入。

# firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="202.XXX.XXX.12" port protocol="tcp" port="22" accept"
# firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="176.XXX.XXX.65" port protocol="tcp" port="22" accept"

で、元々の設定は「誰でも大歓迎」になっているので、その設定を削除。

# firewall-cmd --remove-service=ssh --zone=public --permanent

これで、設定ファイル(/etc/firewalld/zones/public.xml)に書き込まれる。
まだ、この時点では設定ファイルが編集されただけなので、設定ファイルを読み込み直して設定を反映させる。

# firewall-cmd --reload

これで、202.XXX.XXX.12、176.XXX.XXX.65 の IP アドレスからのみ ssh 接続が可能となる。

次に、一時的に接続を許すランタイムルールで職場の PC からの接続を許す。(引数 permanent を付けてないだけ)

# firewall-cmd --zone=public --add-rich-rule="rule family="ipv4" source address="114.XXX.XXX.72" port protocol="tcp" port="22" accept"

設定ファイルには書き込まれないので、reload は不要。即設定が反映する。

必要なくなったら、

# firewall-cmd --zone=public --remove-rich-rule="rule family="ipv4" source address="114.XXX.XXX.72" port protocol="tcp" port="22" accept"

で削除。

旧サーバ(CentOS)では Web 経由で /etc/hosts.allow を編集する仕組みを作って、外出先から一時的に ssh 接続を許すようにしてたんだけど使えなくなっちゃったな。
新しい仕組み作らないと・・・

現在借りているホスティングサーバがとうとう契約切れとなるので(なにせ、OS が CentOS 4.8だからな(笑))、新たに某クラウドサービスを利用して代替サーバを用意したんだけど、OS は AlmaLinux 8.4 にしてみた。

CentOS 7.7、CentOS 8.1 が選べるけど、もう先の無い OS を今更選択するのも賢いやり方ではあるまい。まあ、7.7 を選んでおけば、2024年の 6月いっぱいサポートは受けられるけど(笑)。だからといって今更 7.7 ってのもなあ。

AWS は CentOS Stream が用意されてるんだっけ?
今回契約したクラウドサービスには CentOS、Ubuntu、Debian、そして CentOS 互換の AlmaLinux、Rocky Linux が用意されている。
この選択肢なら、AlmaLinux か Rocky Linux で、一歩先行している(安定版の提供が 1ヶ月ほど早かった)AlmaLinux に決定と・・・。

でも、実際にサーバが使えるようになるのは明日以降。
まだ AlmaLinux を触ったことは無い。なので、実際の CentOS との互換というのはどの程度なのか。

yum は使えるんよなあ???

もし七転八倒することになったら、その様子はこのブログにて(笑)

うちは PHP を使った開発はあまりしないので、開発機の PHP はほったらかしのことが多いのだが、そのサーバを使っているお客さんから「最新の WordPress が入らないのでバージョンアップを」との要請あり。

じゃあ、PHP 7系の最新に・・・と思ったのだが、お客さん都合で「5.6系の最新に」ということになった。

で、PHP を 5.6 に上げたのだが、その後、phpMyAdmin の新規インストールに若干ハマったのでメモ。

現在、この開発機(CentOS 6.9)は「基本的にソースからコンパイルは無し。なるべく yum でパッケージインストール」というルールで運用しているため、今回も yum を使って PHP や phpMyAdmin をインストールした。

問題は phpMyAdmin をインストールしたときに発生した。

# yum --enablerepo=epel install -y phpMyAdmin

と、epel リポジトリを使ってインストールしようとすると、必要な依存ファイルがバージョン 5.6.40 用だから駄目だと怒られる。
確かに PHP は 5.3.3 から 5.6.40 にアップデートした。しかし、epel リポジトリの phpMyAdmin は 5.3.3 用のようだ。

 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest

とか言われるし(^^; 問題あるパッケージは無視して強引に入れちゃえよって???

こりゃあかんと、次は、

# yum -y --enablerepo=remi,remi-php56 install phpMyAdmin

と、remi 及び remi-php56 リポジトリを使ってインストール。すると、今度は 依存ファイルはバージョン 7.0以上の PHP 用じゃないとあかんと怒られるのである。
どうも、PHP 7系用の phpMyAdmin をインストールしようとしているようだ・・・

結局、remi リポジトリにいる最新の phpMyAdmin は PHP 7系用ということなんよねぇ。
なので、解としては、PHP 5.6系用のパッケージが存在しているリポジトリのみを利用すればいいのである。

# yum -y --enablerepo=remi-php56 install phpMyAdmin

これでやっと phpMyAdmin が無事にインストールされたのであった。

という、ぷちハマリの話なのである。
先月からずっと原因も解決策もわからず悶々としてるんだけど・・・

qmail で構築しているメールサーバがあるのね。(qmail を使っていることの是非についての意見は聞きません。qmail 使用でパッケージ化されているシステムなのと、qmail がどうの、オリジナルの sendmail がどうの、postfix がどうこうという話は宗教感の違いでしかないので(笑))

で、そのメールサーバで空メールを受け取ってあれこれ処理をして結果をメールで返してるんだけど・・・

Gmail からメールした時だけ、

The recipient server did not accept our requests to connect. Learn more at https://support.google.com/mail/answer/**20 [mail.exsample.jp. xxx.xxx.xxx.xxx: unable to read banner]

というエラーになる。

IIJ Gio、NTT PC WebARENA、GMO クラウドなどのサーバ上から送信したメールはちゃんと処理される。

また、俺の実メールアドレスに転送する test という alias を作ってテストをしてみても、やっぱり同じエラーになるのでプログラムが悪いわけではない。

そうそう、Yahoo! の Web メールもちゃんと届く。本当にうまくいかないのは Gmail だけなのである。
ちなみに、gmail.com のアカウントから送っても、他のアカウントを From にセットして送っても一緒である。

しょうがないので、さっき postfix でメールサーバを再構築してみた。
そしたら、ちゃんと Gmail から空メールを送ってプログラムを実行することも、test というメールに送って俺の実メールに転送することも成功した。

どうも、Gmail+qmail サーバのみの問題のようだ。

もちろん、qmail サーバの設定がおかしいという可能性もあるが、Yahoo!メールや、他のレンタルサーバ上に構築されたメールサーバからの送信では問題が発生しない。そう考えると qmail の設定の問題というわけではないだろう。

netstat でみると、

tcp        1      0 adm01:smtp              mail-io1-f51.goog:30637 CLOSE_WAIT

という具合に SMTP のポートに接続には来ているようだ。qmail が反応しないんだなあ。

とりあえず、上記のように postfix でシステム再構築をしてうまくいっているのだが、はっきり qmail で駄目だった原因がわからないとどうにもすっきりしない。
原因がわかるという識者の方がいらっしゃれば、ぜひご教授ください。

このアーカイブについて

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

前のカテゴリはMacです。

次のカテゴリはWindowsです。

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

月別 アーカイブ

電気ウナギ的○○ mobile ver.

携帯版「電気ウナギ的○○」はこちら