<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ダメ出し日記 &#187; shell</title>
	<atom:link href="http://www.sfo.jp/blog/archives/category/software/shell/feed" rel="self" type="application/rss+xml" />
	<link>http://www.sfo.jp/blog</link>
	<description>自称・独立&#38;OSS系(?) SE、さとうふみやすの日記。OSS テクノロジ(株)に勤務。</description>
	<lastBuildDate>Fri, 23 Oct 2009 08:10:06 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>ksh: パイプライン前段のプロセスを看取るタイミング</title>
		<link>http://www.sfo.jp/blog/archives/2009/06/ksh-pipeline.html</link>
		<comments>http://www.sfo.jp/blog/archives/2009/06/ksh-pipeline.html#comments</comments>
		<pubDate>Thu, 04 Jun 2009 00:51:40 +0000</pubDate>
		<dc:creator>fumiyas</dc:creator>
				<category><![CDATA[Samba]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[仕事]]></category>

		<guid isPermaLink="false">http://www.sfo.jp/blog/?p=449</guid>
		<description><![CDATA[会社のソフトウェア製品のうち、
Samba 等のデーモン類は、
daemontools (supervise)
で管理するようにしている (一部例外あり)。

Samba の smbd 用の /service/smbd/ [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.osstech.co.jp/">会社</a>のソフトウェア製品のうち、
Samba 等のデーモン類は、
<a href="http://cr.yp.to/daemontools.html">daemontools</a> (<code>supervise</code>)
で管理するようにしている (一部例外あり)。</p>

<p>Samba の <code>smbd</code> 用の <code>/service/smbd/run</code> スクリプトは、
当初は次のようになっていた。
Linux, Solaris ではこれで何も問題なかった:</p>

<pre class="brush: shell; auto-links: false;">
#!/bin/sh
exec 2&gt;&amp;1
exec envdir ./env sh -c &#039;
  echo &quot;PID: $$&quot;
  env |sort |sed &quot;s/^/Environment: /&quot;
  set -- \
    argv0 \
    &quot;$COMMAND&quot; \
    &quot;${ARGV0:-sv:`pwd`}&quot; \
    --daemon \
    --foreground \
    ${CONFIGFILE:+&quot;--configfile=$CONFIGFILE&quot;} \
    ${PORT:+&quot;--port=$PORT&quot;} \
    ${LOGLEVEL:+&quot;--debuglevel=$LOGLEVEL&quot;} \
    ${LOGDIR:+&quot;--log-basename=$LOGDIR&quot;} \
    ;
  echo &quot;Execute: $@&quot;
  exec &quot;$@&quot;
&#039;
</pre>

<p>ところが、某お客さんから、
AIX 6 上で smbd の子プロセスが defunct (ゾンビ) 化するという問題が報告された。
会社の AIX 環境で試したところ、数回に一回程度しか発生しないが、
<code>smbd</code> を起動した直後に発生することがわかった。
発生したときの状態は次のような感じ:</p>

<pre><code># /opt/osstech/sbin/service osstech-smb status
/opt/osstech/etc/svscan/smbd (pid 270496) is running...
# ps -ef |grep 270496 |grep -v grep
    root 270496 258182   0 13:07:27      -  0:00 sv:/var/opt/osstech/lib/sv/smbd --daemon --foreground
    root 282806 270496   0 13:07:27      -  0:00 sv:/var/opt/osstech/lib/sv/smbd --daemon --foreground
    root 295074 270496   0                  0:00 &lt;defunct&gt;
</code></pre>

<p><code>smbd</code> は起動直後にプリンタキュー監視用の子プロセスを生成するので、
これ関連のバグかと思ったが、
<code>ps</code> で見たときちゃんと 2つの <code>smbd</code> が存在するので問題ないように見えた。
<code>smbd</code> を手動で直接起動すると発生しないし、
<code>truss</code> でシステムコールを見たところ、ほかに子プロセスを生成している様子はない。</p>

<p><code>suerpvise</code> か <code>run</code> スクリプトが怪しいと思い、<code>run</code> スクリプトを色々変更してみたところ、
「<code>env |sort |sed 's/^/Environment: /'</code>」
の行をコメントアウトすると再現しないことがわかった。
ということは、パイプライン中のプロセスのいずれかが看取られずに残っているらしい。</p>

<p>また、/bin/sh ではなく bash, zsh, zsh の ksh 互換モードでは再現しないことがわかった。
ちなみに、AIX 6 の <code>/bin/sh</code> は AT&amp;T 由来の Korn Shell (ksh93)。</p>

<p>パイプラインの実行後にそのプロセスが残るのが問題であると推測し、
試行錯誤した結果、次のようなスクリプトで再現することに成功した。
これで、パイプライン実行後に、
実行中の ksh の子プロセスがゾンビ化していることが確認できる:</p>

<pre><code>$ while :;do /bin/ksh -c '/bin/true|/bin/true; ps -f -u $LOGNAME"';done |grep '[d]efunct'
    root 688354 712836   0                  0:00 &lt;defunct&gt;
    ...
</code></pre>

<p>Linux の /bin/ksh (ksh93)、Solaris 10 の /bin/ksh (ksh88) でも再現した。
bash, zsh, ash はもちろん、Linux 上の pdksh (バブリックドメイン版の ksh 実装)
でも再現しなかった。AT&amp;T ksh の仕様らしい。</p>

<p>つまり、こういうこと:</p>

<ol>
<li>ksh は「<code>env |sort |sed "s/^/Environment: /"</code>」を実行したとき、
 パイプラインの最後のプロセス (<code>sed</code>) が終了した時点で以降のスクリプトの実行に進む。
 パイプライン前段のプロセス (<code>env</code>, <code>sort</code>) の終了は待たない。</li>
<li>その後のスクリプト実行中、以前実行したパイプライン前段のプロセスが終了した場合、
 ksh はそれを wait(2) して看取る。</li>
<li>ksh は <code>smbd</code> に exec(2) する。</li>
<li><code>smbd</code> になった時点で以前実行したパイプライン前段のプロセスが残っていた場合、
 それが終了したとき、wait(2) で看取るのは親プロセスである
 <code>smbd</code> プロセスの役目となる。
 しかし <code>smbd</code> はそのことを知らないので wait(2) することはなく、
 結果、子プロセスはゾンビ化する。</li>
</ol>

<p>ksh がパイプライン前段のプロセス終了をどのようなタイミングで、
どのように処理するかまでは確認していないけど、だいたいこんな感じだと思う。</p>

<p>というわけで、<code>run</code> スクリプトは次のようになった。
違いは <code>exec</code> の前に <code>wait</code> を挿入しただけ:</p>

<pre class="brush: shell; auto-links: false;">
#!/bin/sh
exec 2&gt;&amp;1
exec envdir ./env sh -c &#039;
  echo &quot;PID: $$&quot;
  env |sort |sed &quot;s/^/Environment: /&quot;
  set -- \
    argv0 \
    &quot;$COMMAND&quot; \
    &quot;${ARGV0:-sv:`pwd`}&quot; \
    --daemon \
    --foreground \
    ${CONFIGFILE:+&quot;--configfile=$CONFIGFILE&quot;} \
    ${PORT:+&quot;--port=$PORT&quot;} \
    ${LOGLEVEL:+&quot;--debuglevel=$LOGLEVEL&quot;} \
    ${LOGDIR:+&quot;--log-basename=$LOGDIR&quot;} \
    ;
  ## ksh: Ensure that all commands in the pipeline are terminated
  wait
  echo &quot;Execute: $@&quot;
  exec &quot;$@&quot;
&#039;
</pre>

<p>これで無事に問題解決。</p>

<p>シェルスクリプト中ではパイプラインはもちろん、
<code>exec</code> も常用するたちなので、これは困った仕様だなぁ。
<code>exec</code> 前に <code>wait</code> すべし…なんて、バッドノウハウもいいところ。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sfo.jp/blog/archives/2009/06/ksh-pipeline.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>BASH: en_US.UTF-8 で [A-Z] の glob が変?</title>
		<link>http://www.sfo.jp/blog/archives/2008/10/bash-glob.html</link>
		<comments>http://www.sfo.jp/blog/archives/2008/10/bash-glob.html#comments</comments>
		<pubDate>Thu, 16 Oct 2008 13:56:11 +0000</pubDate>
		<dc:creator>fumiyas</dc:creator>
				<category><![CDATA[UNIX]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[ダメ出し]]></category>

		<guid isPermaLink="false">http://www.sfo.jp/blog/archives/2008/10/bash-glob.html</guid>
		<description><![CDATA[
某 CentOS 5 環境で RPM パッケージのビルドが失敗するなぁ〜と思って調べてみた。


$ bash --version
GNU bash, version 3.2.25(1)-release (i686-r [...]]]></description>
			<content:encoded><![CDATA[<p>
某 CentOS 5 環境で RPM パッケージのビルドが失敗するなぁ〜と思って調べてみた。
</p>

<p><pre class="term"><code>$ <kbd>bash --version</kbd>
GNU bash, version 3.2.25(1)-release (i686-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
$ <kbd>touch a b c X Y Z</kbd>
$ <kbd>ls</kbd>
X  Y  Z  a  b  c
$ <kbd>LC<em>ALL=C bash -c 'echo [A-Z]'</kbd>
X Y Z
$ <kbd>LC</em>ALL=ja<em>JP.UTF-8 bash -c 'echo [A-Z]'</kbd>
X Y Z
$ <kbd>LC</em>ALL=en<em>US.UTF-8 bash -c 'echo [A-Z]'</kbd>
b c X Y Z
</code></pre>
<p>
なんじゃこりゃ?
Debian の
GNU bash, version 3.2.39(1)-release (x86</em>64-pc-linux-gnu)
でも同じ挙動だった。
</p>
<p>
やはり<a href="/blog/archives/2007/05/cleanroom.html">クリーンルーム作りは重要</a>だなぁ&#8230;。
</p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.sfo.jp/blog/archives/2008/10/bash-glob.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CentOS の更新パッケージのミラー</title>
		<link>http://www.sfo.jp/blog/archives/2008/05/centos-updates-mirror.html</link>
		<comments>http://www.sfo.jp/blog/archives/2008/05/centos-updates-mirror.html#comments</comments>
		<pubDate>Sat, 17 May 2008 14:56:12 +0000</pubDate>
		<dc:creator>fumiyas</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[仕事]]></category>
		<category><![CDATA[出来事]]></category>
		<category><![CDATA[家族]]></category>

		<guid isPermaLink="false">http://www.sfo.jp/blog/archives/2008/05/centos-updates-mirror.html</guid>
		<description><![CDATA[仕事で沼津へ。
CentOS 5 で OpenLDAP マスターサーバー + Samba PDC + LAM + Usermin をセットアップしたのだが、
CentOS の更新パッケージのダウンロードが超遅く、
作業が [...]]]></description>
			<content:encoded><![CDATA[<p>仕事で沼津へ。
CentOS 5 で OpenLDAP マスターサーバー + Samba PDC + LAM + Usermin をセットアップしたのだが、
CentOS の更新パッケージのダウンロードが超遅く、
作業が予定通り終わらず…。</p>

<p>以前も似たような状況にあったので、今度は更新パッケージを
DVD に焼いていこう。
というわけで、ミラーを実行するスクリプトを作成。
個人的に不要と思われるファイルを除外しているので、
流用する際はご注意を。</p>

<pre class="brush: shell; auto-links: false;">
#!/bin/sh
umask 0022
rsync_opts=&quot;&quot;
while [ $# -gt 1 ]; do
  rsync_opts=&quot;${rsync_opts:+$rsync_opts } $1&quot;
  shift
done
rsync \
  --no-motd \
  --copy-links \
  --hard-links \
  --recursive \
  --times \
  --omit-dir-times \
  --delete \
  --delete-excluded \
  --filter=&quot;. /dev/stdin&quot; \
  $rsync_opts \
  rsync://ftp.riken.jp/centos/ \
  ${1+&quot;$1&quot;} &lt;&lt;EOT_FILTER
## Exclude large unimportant RPMs
- kernel*.src.rpm
- kernel-hugemem*.rpm
- kernel-PAE*.rpm
- xorg-x11*.src.rpm
- tetex*.src.rpm
- openoffice.org*.src.rpm
- firefox*.src.rpm
- thunderbird*.src.rpm
- mozilla*.src.rpm
- seamonkey*.src.rpm
## Exclude unwanted files
- HEADER.*
- .*
## Exclude old releases
- /[1-3]
## Exclude X.Y releases
- /[1-9]*.*
## Include X releases (latest X.Y releases)
+ /[1-9]*
- /[1-9]*/apt
- /[1-9]*/isos*
+ /[1-9]*/*
+ /[1-9]*/*/SRPMS
+ /[1-9]*/*/SRPMS/**
+ /[1-9]*/*/i386
+ /[1-9]*/*/i386/**
+ /[1-9]*/*/x86_64
+ /[1-9]*/*/x86_64/**
## Exclude others
- *
EOT_FILTER
</pre>

<p>帰宅途中、
インターネットで適当に検索して見つけた鰻屋、
<a href="http://www.unayoshi.co.jp/">元祖うなよし</a>
で鰻丼を食べた。
うまかったので鰻蒲焼の真空パックを群馬の両親へ(母の日と父の日を兼ねて)、
自宅には鰻の佃煮を購入。
鰻の骨せんべいも考えたが、
見た目がちょっとグロいというか何というか…だったので止めてしまった。
やっぱり買ってみればよかったなぁ〜。
子供が喜ぶ(?)顔を想像して、買わなかったことをちょっと後悔。</p>

<p>鰻屋から最寄り駅まで勘を頼りに歩いていると、綺麗な小川を発見。
この手の景色と水の音に弱いんだよなぁ〜、いいなぁ〜、と眺めていると、
<a href="http://www.city.mishima.shizuoka.jp/seseragi/route.htm">川の中を歩ける道</a>を発見。
三島駅まで 1.5km くらいの道程を歩いて帰った。
自宅近くにもこんな小川があったらなぁ。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sfo.jp/blog/archives/2008/05/centos-updates-mirror.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>shell: パスの共通部分の切り出し</title>
		<link>http://www.sfo.jp/blog/archives/2007/05/shell.html</link>
		<comments>http://www.sfo.jp/blog/archives/2007/05/shell.html#comments</comments>
		<pubDate>Tue, 29 May 2007 01:26:21 +0000</pubDate>
		<dc:creator>fumiyas</dc:creator>
				<category><![CDATA[shell]]></category>
		<category><![CDATA[仕事]]></category>

		<guid isPermaLink="false">http://www.sfo.jp/blog/archives/2007/05/shell.html</guid>
		<description><![CDATA[
Subversion リポジトリ用の post-commit フックスクリプトを作成中。
コミットされたファイルの一覧からパスの共通部分を求めて、これをメールに含めることにした:


svnlook changed - [...]]]></description>
			<content:encoded><![CDATA[<p>
Subversion リポジトリ用の post-commit フックスクリプトを作成中。
コミットされたファイルの一覧からパスの共通部分を求めて、これをメールに含めることにした:
</p>

<p><pre class="code"><code>svnlook changed -r "$rev" "$repos" \
|awk 'NR==1{p=$2} END{print p} {while(index($2,p)!=1){gsub(/[^\/]<em>\/</em>$/,"",p)}}'
</code></pre>
<p>
パスに空白文字が含まれることは想定していない。
</p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.sfo.jp/blog/archives/2007/05/shell.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>shell: 自己を展開し、configure, make, make install する</title>
		<link>http://www.sfo.jp/blog/archives/2007/02/shell-selfbuilder.html</link>
		<comments>http://www.sfo.jp/blog/archives/2007/02/shell-selfbuilder.html#comments</comments>
		<pubDate>Fri, 16 Feb 2007 17:40:23 +0000</pubDate>
		<dc:creator>fumiyas</dc:creator>
				<category><![CDATA[UNIX]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.sfo.jp/blog/archives/2007/02/shell-selfbuilder.html</guid>
		<description><![CDATA[
ミラクル・リナックスの blog の記事:
SCRIPT HACKS &#8211; 第1回「make install はもう古い？」
ネタ。



自己展開型のシェルスクリプトを初めて見たのは 10年以上前だろうか? [...]]]></description>
			<content:encoded><![CDATA[<p>
ミラクル・リナックスの blog の記事:
<q><a href="http://blog.miraclelinux.com/asianpen/2007/02/script_hacks_1m_8424.html">SCRIPT HACKS &#8211; 第1回「make install はもう古い？」</a></q>
ネタ。
</p>

<p><p>
自己展開型のシェルスクリプトを初めて見たのは 10年以上前だろうか?
Solaris か SunOS 4 用の何かのインストールスクリプトだったかな。
当時はエラく感動したような気がするが、今では自力でさくっと実装できてしまう。
楽しい。しかし、それだけ年をとったということか。
</p>
<p>
試しに、自身に含まれるソースアーカイブを展開し、
<code>make</code>, <code>make install</code>
するシェルを作ってみた。
モノは以下のような感じ。
名前は <code>selfbuilder.sh</code> としよう。
</p>
<pre class="code"><code>#!/bin/sh</p>

<h1>#</h1>

<h2>Shell Demo: Self-'extract, configure, make and install' script</h2>

<h2>Copyright (c) 2007 SATOH Fumiyasu @ <a href="http://www.osstech.co.jp/">OSS Technology Co.</a>, Japan</h2>

<h1>#</h1>

<h2>Date: 2007-02-17, since 2007-02-17</h2>

<h2>License: GNU General Public License version 2</h2>

<h1>#</h1>

<h2>Usage:</h2>

<h1>#</h1>

<h2>Make a selfbuilder:</h2>

<h2>$ cat selfbuilder.sh &gt;archive-installer</h2>

<h2>$ echo archive.tar.gz &gt;&gt;archive-installer</h2>

<h2>$ cat archive.tar.gz &gt;&gt;archive-installer</h2>

<h1>#</h1>

<h2>Install by the selfbuilder:</h2>

<h2>$ chmod +x archive-installer</h2>

<h2>$ sudo ./archive-installer</h2>

<h1>#</h1>

<p>set -u
set -e
umask 0077
tmp<em>dir="/tmp/.selfbuilder.$$.<code>date +%s</code>.tmp"
trap 'rm -rf "$tmp</em>dir"' 0 HUP INT QUIT TERM PIPE
mkdir "$tmp<em>dir"
cat "$0" | (
while read line; do
if [ x"$line" = x"EOS" ]; then
break
fi
done
read filename
(
case "$filename" in
<em>.bz2|</em>.tbz2)
bzip2 -d
;;
<em>.gz|</em>.tgz)
gzip -d
;;
<em>.Z|</em>.tz)
uncompress
;;
*)
cat
;;
esac
) |(cd "$tmp</em>dir" &amp;&amp; tar xf -)
)
cd "$tmp_dir"/*
./configure
make
make install
exit 0
EOS
</code></pre>
<p>
使い方の例:
</p>
<pre class="terminal"><code>$ <kbd>cat selfbuilder.sh &gt;samba-installer</kbd>
$ <kbd>echo samba-3.0.24.tar.gz &gt;&gt;samba-installer</kbd>
$ <kbd>cat samba-3.0.24.tar.gz &gt;&gt;samba-installer</kbd>
$ <kbd>chmod +x samba-installer</kbd>
$ <kbd>sudo ./samba-installer</kbd>
<var>...Samba のソースが展開、ビルド、インストールされる...</var>
</code></pre>
<p>
Google のスクリプトはわざわざ <code>dd</code> を使っているが、<code>cat</code> で十分じゃないかしら
(誰か、dd と cat の速度と負荷の比較をしてくれないかなぁ?)。
また、シェルスクリプトの最後に目印を埋め込んでおけば、スクリプト部分のサイズをベタ書きしなくても済む。
</p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.sfo.jp/blog/archives/2007/02/shell-selfbuilder.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>shell: パス経路の ls -ld</title>
		<link>http://www.sfo.jp/blog/archives/2006/11/shell-ls-ld.html</link>
		<comments>http://www.sfo.jp/blog/archives/2006/11/shell-ls-ld.html#comments</comments>
		<pubDate>Wed, 29 Nov 2006 08:29:42 +0000</pubDate>
		<dc:creator>fumiyas</dc:creator>
				<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.sfo.jp/blog/archives/2006/11/shell-ls-ld.html</guid>
		<description><![CDATA[
ファイル自身のパーミッションでなく、
そこまでの経路のパーミッションの問題の可能性がある場合、
どうやって確認するか。
ls コマンドにないのかしら。


#!/bin/sh
p="$1"; shift
while t [...]]]></description>
			<content:encoded><![CDATA[<p>
ファイル自身のパーミッションでなく、
そこまでの経路のパーミッションの問題の可能性がある場合、
どうやって確認するか。
ls コマンドにないのかしら。
</p>

<p><pre class="code"><code>#!/bin/sh
p="$1"; shift
while true; do
ls -ld "$@" "$p"
p="<code>expr "$p" : '\(.*\)/'</code>" || break
done
</code></pre>
<p>
いまいち。
</p>
<pre class="terminal"><code><ins>$ <kbd>sudo -u <var>username</var> test -r <var>/path/to/target</var>; echo $?</ins>
<del>$ <kbd>sudo setuidgid <var>username</var> test -r <var>/path/to/target</var>; echo $?</kbd></del>
</code></pre>
<p>
su でやる方法もあると思うが、これが一番シンプルかな。
2007年1月26日 更新: <code>setuidgid</code> ではなく <code>sudo</code> の <code>-u</code> オプションに変更。
</p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.sfo.jp/blog/archives/2006/11/shell-ls-ld.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

