wordpressで更新をかけて失敗してもう一度更新をかけたりすると「別の更新が現在進行中です。」なんて文言が出てきて15分ぐらいしないと再度更新処理ができないという仕様がかなりイラッとするけど設定で回避策がなさそうだから直接コードを書き換えるの巻

このサイトはwordpressを使っている。ときどきwordpress本体の更新がかかるが、更新をかけてから、何らかの理由で処理が失敗することがある。で、そのあともう一度更新をかようとすると「別の更新が現在進行中です。」という文言が出てくる。何度更新ボタンを押してもだめ。「しばらくしてから」って、いったいどのくらいだよって思ってググると、みなが口を揃えて「15分ぐらいしないと」と記載している。しかし、急いで更新して外出したいのに、そんな15分なんてハンパな時間は待ってられない!重複して更新処理が走るのを回避しているという実装はわかるが、自分一人でしか面倒みてないブログなので、ぶっちゃけイラッとするのだ。ということで、強制的に処理を進めさせるべく、コードを一部修正して更新を継続させる。 “wordpressで更新をかけて失敗してもう一度更新をかけたりすると「別の更新が現在進行中です。」なんて文言が出てきて15分ぐらいしないと再度更新処理ができないという仕様がかなりイラッとするけど設定で回避策がなさそうだから直接コードを書き換えるの巻” の続きを読む

[自分用メモ] Redmineのガントチャートのデフォルト開始月を当月の1ヶ月前にする修正

Redmineの、特にガントチャートに関する修正要求が職場で結構多い。rubyは使ったことも勉強したこともないのだけれど、それでも要求に応じて修正をしなければならない。まあエンジニアとしてある程度好きにやらせてもらっている以上はdutyを払う必要はあると思っているので、こういうことも嫌がらずにやるしかないのである。 “[自分用メモ] Redmineのガントチャートのデフォルト開始月を当月の1ヶ月前にする修正” の続きを読む

人生で初めてrubyのソースを見た日、人生で初めてRedmineのソースコードをいじった日

仕事でRedmineを使っている。といっても、私はたいして使ってない。この手のツールは苦手なのだ。でも仕事上社内で使っている人は多い。
今日はその部分改修を要望されてしまった。ガントチャートをズームしたときに、最大ズーム時に曜日と日が重なって見えないというのだ。 “人生で初めてrubyのソースを見た日、人生で初めてRedmineのソースコードをいじった日” の続きを読む

WordPressの抜粋表示プラグイン「Thumbnail for Excerpts」が日本語対応じゃなかったので対応してみた

このブログはWordPressを使っている。プラグインもそれなりに充実しているし設定も簡単なので重宝している。
テーマはデフォルトのTwenty Elevenを使っているけれど、特に不満らしい不満はない。ただ、トップページ(Home)の表示が全記事表示になってしまっていて、長い記事を書くとかなりウザい状況になる。なので、記事の最初の方だけ表示する抜粋表示をするように調整するためのプラグインを探してみた。 “WordPressの抜粋表示プラグイン「Thumbnail for Excerpts」が日本語対応じゃなかったので対応してみた” の続きを読む

UID最大値

仕事でアカウントをmergeする必要がでてきたんだけれど、それぞれ別の文化で作成してきたアカウントを1つに結合するわけだから、ユーザ名はもちろんのこと、UIDやGIDも競合する。

ユーザ名は仕方がないので個別に当たっていくしか方法がないのだが、UIDとGIDはどうしようかと思案した結果、一方のUID/GIDにゲタをはかせるしかないと結論した。

passwdコマンドで試しにUIDやGIDに100000とかを入れてみると、「100000 > recommended max uid value (65535)」とか表示されるものの、OK。このメッセージを吐いてる場所を一応確認すると、pw_bin_ids_warningなフラグが立っていると警告するらしい。

src/lib/libc/gen/pw_scan.c

if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
warnx("%s > recommended max uid value (%u)", p, USHRT_MAX);
/*return (0);*/ /* THIS SHOULD NOT BE FATAL! */
}

ま、それより、本当はどこまで大丈夫なのかしらと、src/usr.bin/passwd/passwd.cから見て見たら、pwd.hをincludeしている模様。なので/usr/include/pwd.hを覗いてみる。

と、ほらpasswd構造体。
uid_tとかgid_tとかあるね。この型が何かがわかればいい。たぶんunsigned intあたりだと思うのだが。


struct passwd {
char *pw_name; /* user name */
char *pw_passwd; /* encrypted password */
uid_t pw_uid; /* user uid */
gid_t pw_gid; /* user gid */
time_t pw_change; /* password change time */
char *pw_class; /* user access class */
char *pw_gecos; /* Honeywell login info */
char *pw_dir; /* home directory */
char *pw_shell; /* default shell */
time_t pw_expire; /* account expiration */
int pw_fields; /* internal: fields filled in */
};

sys/_types.hをincludeしてるから、このあたりかしら。
ほらほらあった。


      :
      :
typedef __uint32_t __gid_t;
      :
      :
typedef __uint32_t __uid_t;
      :
      :

__gid_tとかは、pwd.hでgid_tとかでdefineされてるので、uint32ってことで100000のゲタを履かせて対応することに決めた。


      :
      :
#ifndef _GID_T_DECLARED
typedef __gid_t gid_t;
#define _GID_T_DECLARED
#endif
      :
      :
#ifndef _UID_T_DECLARED
typedef __uid_t uid_t;
#define _UID_T_DECLARED
#endif
      :
      :

でも、Mac OS Xでも使うのよね(OpenLDAP認証)。
FreeBSD由来だから同じだとは思うんだけれど、Mac OS XでもUID/GIDは問題なく32bitでいいのかなぁ…。
[ad#ultrah]

dhcp-4.1.0a1をinstallしてみた

ISC DHCP 3.0.6をインストールしているマシンがあって、去年秋口にdhcp-3.1.0のリリースに合わせてバージョンアップをしようと思って作業をしていた。

ISC DHCPにはてこずった試しがないので、気軽にmake & installをしたのだが、makeは問題なく通過したものの、dhcpdを再起動したら、

Internal inconsistency: storage value has not been initialized to zero (from auth.c:112).

というエラーで動かなくなってしまった。
あせってその時はdhcp-3.0.6に戻して事なきを得たのだが、原因究明をする暇もなくそのまま今日まで身を潜めていた私であった。

そして今日。

別に、思い立ったわけじゃないんだけれど、dhcp4系なら直ってるかなぁと思ってdhcp-4.1.0a1を試してみた。

やっぱり、同じエラーが出た。
がっかりだよ。

で、このままだと3.0.6を使いつづけなければならなくなるので、時間を作ってsourceを追うことにした。っていうのは、ぐぐっても何も情報が得られなかったから。ってことは、かなり特殊な事情なんではなかろうか…。先行き暗い。

ヒントはauth.cの112行目。まずはこれを見る。

[omapip/auth.c]

107: isc_result_t omapi_auth_key_lookup_name (omapi_auth_key_t **a,
108: const char *name)
109: {
110: if (!auth_key_hash)
111: return ISC_R_NOTFOUND;
112: if (!omapi_auth_key_hash_lookup (a, auth_key_hash, name, 0, MDL))
113: return ISC_R_NOTFOUND;
114: return ISC_R_SUCCESS;
115: }

omapi_auth_key_hash_lookup()の呼び出し元を探す。
しかしながら、omapi_auth_key_hash_lookup()というのは、どこをgrepしても、ない。
ま、こりゃあれだな。#defineでname##とかやってるパターンだろって思ったら、やっぱりそうだった。hash.hの中で宣言されている。

[includes/omapip/hash.h]

111: int name##_hash_lookup (type **ptr, hashtype *table, \
112: bufarg buf, unsigned len, const char *file, int line) \
113: { \
114: return hash_lookup ((hashed_object_t **)ptr, \
115: (struct hash_table *)table, \
116: buf, len, file, line); \
117: } \

そして、以下の宣言がhash.cの先頭のほうに。

[omapip/auth.c]

40: typedef struct hash omapi_auth_hash_t;
41: HASH_FUNCTIONS_DECL (omapi_auth_key, const char *,
42: omapi_auth_key_t, omapi_auth_hash_t)
43: omapi_auth_hash_t *auth_key_hash;
44: HASH_FUNCTIONS (omapi_auth_key, const char *, omapi_auth_key_t,
45: omapi_auth_hash_t,
46: omapi_auth_key_reference, omapi_auth_key_dereference,
47: do_case_hash)

hash_lookup()はhash.c中にある。中を覗くと、すぐにわかった。

[omapip/hash.c]

487: if (*vp != NULL) {
488: log_fatal(“Internal inconsistency: storage value has not been ”
489: “initialized to zero (from %s:%d).”, file, line);
490: }

ていうか、実は最初にgrep “storage value” *とかで漁って、目星をつけてから上のやり方で呼び出しを調べたりしていたので、実際に作業した順番とは違ったりするが、まぁこんな感じで、ここが呼ばれているのがわかった。

この後、いろいろ試行錯誤して、server/dhcpd.cとかまで戻って調べたりしたのだけれど、どうにも理解できない。しかも設定ファイルのパラメータは構造体とポインタで深く深く作り込まれていて、quick hackはちょっと難しそう。dhcpdを解析するんじゃなくて、エラーの原因を知りたいので、強引な手段に出ることにした。

printf()デバッグをする。

以下の486行目を新たに追加して、結果を見てみることにした。
吉と出るか凶と出るか。
あ、凶は出ないか。どのみち最悪の事態だし。

486:printf(“>>>>>>>%s\n”,key);
487: if (*vp != NULL) {
488: log_fatal(“Internal inconsistency: storage value has not been ”
489: “initialized to zero (from %s:%d).”, file, line);
490: }

いろいろ調べてみた結果から、「int hash_lookup (vp, table, key, len, file, line)」のkeyは(omapi_auth_key_hash_lookup()の場合には)char*型であることが分かっていたので、printf()デバッグが有効であることが分かったので、この行を追加してmake & install。

結果は、以下のように出た(これ出すまでに、いくつか試行錯誤してたのですが)。

Internet Systems Consortium DHCP Server 4.1.0a1
Copyright 2004-2008 Internet Systems Consortium.
All rights reserved.
For info, please visit http://www.isc.org/sw/dhcp/
>>>>>>>>?
>>>>>>>>Q
>>>>>>>>|
>>>>>>>>}
>>>>>>>>?
>>>>>>>>
>>>>>>>>?
>>>>>>>>’
>>>>>>>>R
>>>>>>>>
>>>>>>>>server
>>>>>>>>ddns-hostname
>>>>>>>>fqdn
>>>>>>>>hostname
>>>>>>>>host-name
>>>>>>>>server
>>>>>>>>ddns-domainname
>>>>>>>>domain-name
>>>>>>>>server
>>>>>>>>ddns-ttl
>>>>>>>>server
>>>>>>>>ddns-rev-domainname
>>>>>>>>server-name
>>>>>>>>ddns-update-style
>>>>>>>>update-static-leases
>>>>>>>>ping-check
>>>>>>>>omapi-port
>>>>>>>>domain-name-servers
>>>>>>>>domain-name
>>>>>>>>ddns-domainname
>>>>>>>>ddns-rev-domainname
>>>>>>>>default-lease-time
>>>>>>>>max-lease-time
>>>>>>>>use-host-decl-names
>>>>>>>>www-server
>>>>>>>>ntp-servers
>>>>>>>>nntp-server
>>>>>>>>wpad
>>>>>>>>
>>>>>>>>wpad
>>>>>>>>log-facility
>>>>>>>>
>>>>>>>>(
>>>>>>>>dhcp_ddns
>>>>>>>>dhcp_ddns
>>>>>>>>sub01.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub02.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub03.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub04.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub05.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub06.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub07.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub08.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub09.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub10.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub11.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>sub12.example.co.jp.
>>>>>>>>dhcp_ddns
>>>>>>>>dhcp_ddns
Internal inconsistency: storage value has not been initialized to zero (from auth.c:112).

あれ?
sub12.example.co.jpで終わってしまってる。
設定ファイルはもっと長いのに。

一体どこで終わってるのか調べてみた。
すると、dhcpd.conf中の、DDNS設定のためのzoneステートメントを設定している箇所の一部に、重複設定が見つかった。

zone sub13.example.co.jp. {
primary 192.168.10.20;
key dhcp_ddns;
key dhcp_ddns;
}

がが〜ん!!

いつの間にこんなのが…ファイル自体は2005年の夏からずっといじられていないし、構成も変わっていないから、こんなのが入っているってことは、当初からそのままだったっていうことか…。

開発の中で、本来バグあるいは仕様として問題がある部分が改修されたためなのか、3.0.6までは問題なかった設定が、3.1.0以降のsourceではさきのエラーが出るようになってしまったというのがオチのようだ。

具体的な原因や、しっかりしたhackに基づく結論じゃないので生煮えな気分ではあるが、設定ファイルの誤記によって、いままで動いていたものが動かなくなることはありうるらしい。しかも、予想していなかった(つまり、いままでエラー処理されてこなかった?)設定でいきなり動かなくなるという副作用は、ままあるのだということを思い知らせるのであった。

いい勉強になりました。

[ad#ultrah]

Phaser 6201Jの拡張トレイ3で印刷するためにPostScriptファイルに突っ込んだコード

ほとんど仕事メモですね。すみません。
Phaser 6201Jという古典的PSプリンタを、さる理由で入手。
仕事場で活用していたのですが、従来のRICOHで吐けた、トレイ指定のPSファイルが吐けなくなってしまい、しかたがないのでWindowsのPhaser 6201Jのドライバにオートフィードへの出力ととトレイ3への出力のPSファイルをそれぞれ吐かせて(「ファイルに出力」チェックがあるので、プリンタではなくファイルにPSを保存できる)、diffをとった部分を試しに突っ込んだらビンゴでした。

で、突っ込んだのは、これ。
PSファイルの先頭に突っ込んでも問題なくトレイ3から印刷できる模様。
本当はPostScriptの仕様を理解して適切に指定する必要があるのでしょうが、そんなことにモチベーションは高められない昨今…。

%%BeginFeature: *InputSlot LowerSheetFeeder
currentpagedevice /InputAttributes get dup 2 known
{2 get dup null eq
{ pop }
{ dup length 1 add dict copy
dup /InputAttributes
1 dict dup /Priority [2 0 1] put
put setpagedevice
} ifelse }
{pop}
ifelse
1 dict dup /TraySwitch false put setpagedevice
%%EndFeature

bindに埋め込まれたroot servers

L-root serverのIPv4アドレス変更の話題の中で、[DNSOPS dnsops 320]の話が出た。
それへのreplyとして[DNSOPS dnsops 321]があがったので、ようやく時間を見つけてbindのソースを簡単に追ってみた。

[DNSOPS dnsops 321]で言われてるlib/dns/rootns.cに、以下の文字列が指定されている(ML本文を読み返さずgrepして調べてしまった)。ちなみにこれ、bind-9.4.2のsource treeね。

static char root_ns[] =
:
:
“L.ROOT-SERVERS.NET. 3600000 IN A 199.7.83.42n”

このroot_nsを参照しているのは何かというと、lib/dns/rootns.c中のdns_rootns_create()内である。ここでisc_buffer_init()の呼び出し時の引数として渡している。

isc_buffer_init(&source, root_ns, len);

このようにして、root NSを生成しているのだが、じゃあdns_rootns_create()を呼び出して生成をしようとしている人は一体誰なのか。
bin/named/server.c中のconfigure_hints()関数が呼び出していた。

result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);

名前からも想像してしまうが、hintsファイルつまりnamed.root(named.confで指定可能だからファイル名は違う場合もある)をroot NSとしてzone DBを構築しようとしているわけだ。dns_rootns_create()の第1引数のview->mctxは、指定view(namedではviewという概念がある)のメモリコンテクストだと想像する(想像ね)。namedが管理するviewごとのzone情報は、メモリに蓄積されているわけだから(nsupateが入ると、ときどき.jnlファイルを更新したりzoneファイルに反映したりする)、named.conf中で指定された

zone “.” {
type hint;
file “named.root”;
};

というような設定を含むviewにroot NSの設定ファイルの中身を反映させるというわけだ、と思う。
ところでconfigure_hints()ファイルはどこで呼ばれているかというと、bin/named/server.cファイル中で呼び出しを行っている。

result = configure_hints(view, hintsfile);

指定されたviewにヒントファイル(このファイル名は、そのままdns_rootns_create()の第3引数に引き継がれる)のデータを突っ込むのだが、じゃあroot_nsは一体いつのタイミングで使われるわけ?ってのが、同じくbin/named/server.cファイル中の、おそらく以下の部分。

if (dns_name_equal(origin, dns_rootname)) {
const char *hintsfile = cfg_obj_asstring(fileobj);

result = configure_hints(view, hintsfile);
if (result != ISC_R_SUCCESS) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER,
ISC_LOG_ERROR,
“could not configure root hints ”
“from ‘%s’: %s”, hintsfile,
isc_result_totext(result));
goto cleanup;
}

dns_rootnameは上手に追えてないのですが、static dns_name_t rootをそのまま参照しているだけのポインタだと思われる(それ以外で、どこかで代入されている形跡はgrepできんかった)。
originはこれまた上手に追えていません。上記コードが置かれたconfigure_zone()内の初めの方で、以下のように代入したまま変更のない値を使っている模様。

origin = dns_fixedname_name(&fixorigin);

fixoriginっていうのは、configure_zone()の第2引数zconfigを元にメンバ変数を生成している。zconfigは、さらに呼び出し元であるconfigure_view()の中を見る限りでは、named.conf中の現時点でのviewステートメント中にあるzoneステートメントを指しているんじゃないかしらと仮定。その中でさらにhintを見付け、file指定子を探し、dns_name_equal()に至っている。
dns_name_equalで、両者構造体中のメンバ変数ndataを(attributesメンバ変数なども参照して厳密に)比較しているので、DNS的rootの基準であるdns_rootnameと比較することで「zone “.” { … };」を検出、そうであればconfigure_hints()を呼ぶことにしている、と想像する。

configure_hints()で呼び出されると、さきほど辿ってきた関数群をどんどん進み、最初に出てきたlib/dns/rootns.c中のdns_rootns_create()の中にある、この部分に突き進む。

if (filename != NULL) {
/*
* Load the hints from the specified filename.
*/
result = dns_master_loadfile(filename, &db->origin,
&db->origin, db->rdclass,
DNS_MASTER_HINT,
&callbacks, db->mctx);
} else if (rdclass == dns_rdataclass_in) {
/*
* Default to using the Internet root servers.
*/
result = dns_master_loadbuffer(&source, &db->origin,
&db->origin, db->rdclass,
DNS_MASTER_HINT,
&callbacks, db->mctx);

filenameはnamed.conf中で指定しているヒントファイルだが、これがNULLでなければ、このファイルからroot NSを読み込んでzone DBに突っ込んでいる。
root_nsが使われるのは、else ifの条件にひっかかった場合だ。最初の「isc_buffer_init(&source, root_ns, len);」のとおり、sourceがデフォルトのroot NSのデータを示すオブジェクトとして指定されているので(たぶんね)、dns_master_loadbuffer()でデフォルトのroot serversが突っ込まれることになる。

だから、named.conf中でnamed.root(ヒントファイル)の指定がない場合にはroot_ns[]つまり内蔵されたroot serversデータが使用される。したがって、L-root serverのIPv4が変更される前のbindを使っていて、かつヒントファイルの指定がない場合のみ、L-root serversが古いまま参照され続けてしまうということになる。

あ〜、疲れた…。
てか、これであってるのかしら?(保証なし)