お仕事: 2014年9月アーカイブ

いやあ、久しぶりに規模的にヤバいセキュリティ問題発生っすねえ。

だって、bash が入ってない UNIX マシンなんか無いやろ?いや、あるだろうけど、相当の変わり者のマシンだろ、それ。

OS の開発元(Linux の各ディストリビュータとか)からのパッチや、修正版パッケージの提供があればいいけど、ないとソースから make し直しか。それだと影響範囲の調査とか面倒くさそう・・・

ということで、取り敢えずうちのテストサーバで対応作業を確認してみた。

このテストサーバに入っている bash が、

# rpm -aq|grep bash
bash-3.2-32.el5

ということで、もろに問題のある Bash 3.2系(^^;
OS は CentOS release 5.8 (Final)なので、[CentOS-announce] CESA-2014:1306 Important CentOS 5 bash Security Update を確認してみると、セキュリティパッチの当たったパッケージ bash-3.2-33.el5_10.4.x86_64.rpm が提供されているようだ。

yum で確認してみる。

# yum list|grep bash
bash.x86_64                            3.2-32.el5                 installed
bash.x86_64                            3.2-33.el5_10.4            updates

ふむふむ。
updates だけ確認するときは、

# yum list updates|grep bash
bash.x86_64                       3.2-33.el5_10.4                     updates

でもOK。
おお、確かに updates ってことで、3.2-33.el5_10.4 が提供されている。

取り敢えず 3.2-33.el5_10.4 をインストール。
途中で依存関係を確認したいので、-y オプションは無しで。

# yum update bash
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * addons: ftp.iij.ad.jp
 * base: ftp.iij.ad.jp
 * centosplus: ftp.iij.ad.jp
 * contrib: ftp.iij.ad.jp
 * extras: ftp.iij.ad.jp
 * updates: ftp.iij.ad.jp
Excluding Packages in global exclude list
Finished
Setting up Update Process
Resolving Dependencies
--> Running transaction check
---> Package bash.x86_64 0:3.2-33.el5_10.4 set to be updated
--> Finished Dependency Resolution

Dependencies Resolved

=======================================================================================================================================================================================
 Package                                 Arch                                      Version                                            Repository                                  Size
=======================================================================================================================================================================================
Updating:
 bash                                    x86_64                                    3.2-33.el5_10.4                                    updates                                    1.8 M

Transaction Summary
=======================================================================================================================================================================================
Install       0 Package(s)
Upgrade       1 Package(s)

Total download size: 1.8 M
Is this ok [y/N]: 

特に他のソフトが update されてしまうということは無いみたい。それなら問題ないので y を入力して先に進む。

Downloading Packages:
bash-3.2-33.el5_10.4.x86_64.rpm                                                                                                                                 | 1.8 MB     00:00
Running rpm_check_debug
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
  Updating       : bash                                                                                                                                                            1/2
  Cleanup        : bash                                                                                                                                                            2/2

Updated:
  bash.x86_64 0:3.2-33.el5_10.4

Complete!

インストールされたか確認。

# rpm -aq|grep bash
bash-3.2-33.el5_10.4

バッチリね。
CentOS はパッチ適用済みのパッケージが提供されているので対応も簡単にすみそう。

ちなみに、bash シェルにリモートログインして上記作業を行っても(bash の入れ替えをしても)、途中で回線が切れちゃうなんてことはないのでご安心を。
VB.NET で、データセットから作成したビューのレコードを、ループさせながらインデックス指定で直接削除すんなよという話。

インデックスを指定してレコードを削除する場合も、例えば、

view.AllowDelete = True
Do
    Dim i As Integer = view.Find("消したいレコードに含まれているキーワード")
    If i <> -1 Then
        view.Delete(i)
    Else
        Exit Do
    End If
Loop

みたいな使い方であれば問題ないんだけど、ループしながらインデックスをアップしつつ消しちゃうと、その瞬間にレコードが削除されたことでその後のレコードのインデックスが変化してしまい、正常にデリートできない(削除予定のレコードが並んでいた場合、次のレコードを飛ばしちゃうことになっちゃう)という話。
ビューの Delete メソッドは直接レコードを削除しちゃうんだよね。

例えば、

view.AllowDelete = True
Dim max As Integer = view.Count - 1
For i = 0 To max
    if view(i).hoge = "消したいレコードに含まれているキーワード" Then
        view(i).Delete()
    End If
Next

みたいにしちゃうと、view(i).Delete() しちゃった時点で、以降のレコードのインデックスがひとつ減っちゃう。
本来、view(i + 1) だったレコードが view(i) になっちゃうということ。
つまり、上に書いたように、削除予定のレコードが並んでた場合、削除したレコードの次のレコードの処理は飛ばされてしまうということだ。あかん。

どうしてもビューの中身を頭から舐めながら処理を行いたい場合は、一旦データテーブル等にコピーして処理を行う必要がある。

Dim dt As HogehogeDs.hogeDataTable = CType(view.Table, HogehogeDs.hogeDataTable)
Dim max As Integer = dt.Count - 1
For i = 0 To max
    If dt(i).hoge = "消したいレコードに含まれているキーワード" Then
        dt(i).Delete()
    End If
Next
dt.AcceptChanges()
view = dt.DefaultView

みたいな感じ。

データテーブルの Delete メソッドはビューと違って「実際に削除するのではなく、削除マークをつけるだけなので、最後に AcceptChanges するまではインデックスが変化することもなく、問題なく最後まで削除処理を行うことができる。

これも、知らずにやっちゃうと相当ハマる。特に、レコード件数が多い時はデバッグで問題を見つけ出すのも大変(^^;
今やってる仕事、帳票の出力には VB-Report 8 を使っている。
これ、帳票定義が Excel シートで作成出来るスグレモノなんだけど(Excel でセルを結合したり、罫線を引いたりして帳票のデザインを行ったら、あとは簡単なプログラムで帳票出力できる)、意外にネット上に情報がなくて俺みたいな初めて使うもんには困るわあ。

情報が無いっつうか、古いんだよな。だいたい、Ver 3 の頃の情報ばっか引っかかる。

開発ツールについてきてるヘルプを使えば良いっつう話なんだけど、このヘルプがこれまたなかなか情報までたどり着きづらいというか(^^;(あくまで、俺みたいに初めて使う人間の意見だけど)

Ver 3 の頃と 8 では大きくプロパティが変わってるんだけど、ヘルプの検索でもなかなか引っかからなくて弱った(^^;
例えばプログラムの中で動的に「セルの結合」がしたかったんだけど、「キーワード」や「検索」で「セル結合」とか入れてもなんもヒットせんし(^^;

結局、

【セルの結合】
3.0 Report.Pos(x1, y1, x2, y2).Attr.Joint = True
 ↓
8.0 Report.Pos(x1, y1, x2, y2).Attr.MergeCells = True

みたいに変わってたんだけど、「Joint」とか入れてもヘルプじゃなんもヒットせんしさあ。
こういうの、過去のバージョンの内容と変わったものについてもっと考慮してほしいなあ。

【縮小して全体表示】
3.0 Report.Pos(x1, y1).Attr.Fit = True
 ↓
8.0 Report.Pos(x1, y1).Attr.ShrinkToFit = True

これも、「Fit」じゃ何の情報も見つからなくて、もちろん「ShrinkToFit」って入れればヒットするんだけど(^^;
「ShrinkToFit」がわかんないから検索してんのに(^^;

まあ、さすがにこれだけ名前が変わってるってのがわかれば、PosHorz は、プロパティの一覧を頭から舐めていって、ああ、この HorizontalAlignment に変わったんだろうなあと想像はつくが・・・

ちなみに、中央揃えは、

Report.Pos(x1, y2).Attr.HorizontalAlignment = VBReport8.HorizontalAlignment.Center

だ。
VB.NET の話。

DataSet には並び替えの概念はないので、DataSet の表をソートしようとすると、その DataSet から DataView を作って、それを Sort メソッドで並び替えるしか無いわけだけど、検索(行の抽出)だけであれば DataSet の中で行える。

昨日アップしたエントリーでは、

Dim dv As DataView = ds.hoge_table.DefaultView
dv.RowFilter = "hoge_time >= #" & hogeTime.ToString & ".00000# Or hoge_time <= #" & hogeTime.ToString & ".99999#"
dv.Sort = "key1, key2"
For Each drv As DataRowView In dv
    Dim dr As HogehogeDataSet.hoge_tableRow = CType(drv.Row, HogehogeDataSet.hoge_tableRow)
    dr.key1 をほげほげ~
Next

という処理のことを書いたけど、この Sort メソッドを実行しない・・・という前提なら(つまり検索(抽出)をしたいだけなら)、DataTable の Select メソッドを使えば、検索(抽出)した結果が配列で取れるので、

Dim filter As New Text.StringBuilder
filter.Append("hoge_time >= #" & hogeTime.ToString & ".00000# Or hoge_time <= #" & hogeTime.ToString & ".99999#")
Dim drList() As DataRow = ds.hoge_table.Select(filter.ToString)
For Each dr As HogehogeDataSet.hoge_tableRow In drList
    dr.key1 をほげほげ~
Next

という感じで良い。

ステップ数は変わらないけど、抽出のためだけにビューを作らないので俺はこっちの方が好みだな。
ソートする時はどうしようもないけど(^^;

一応、メモ代わりに書いとくなり。
結局、これってミリ秒までマッチングする必要がないのなら、格納時に、

Dim hogeTime As DateTime = Now

じゃなく、

Dim hogeTime As DateTime = CDate(Now.ToString)

みたいにして、ミリ秒を削った時間(まあ、実際は 0ミリ秒になるってことだけど)をセットしてやれってことか。

こうすると、hogeTime には実際の時刻が 2014/09/04 18:37:36.5685248 であろうと、2014/09/04 18:37:36.0000000 という値がセットされるので、

dv.RowFilter = "hoge_time = #" & hogeTime & "#"

という条件でマッチングするようになる。

dv.RowFilter = "hoge_time >= #" & hogeTime.ToString & ".00000# Or hoge_time <= #" & hogeTime.ToString & ".99999#"

みたいに長ったらしい条件書かなくてもいい。

つーか、この長ったらしい条件、やっぱダメだよね。
例えば、これじゃあ 2014/09/04 18:37:36.9999999(小数点以下 7桁)の時間はマッチしないよね。条件が <= 2014/09/04 18:37:36.99999(小数点以下 5桁)だから。18:37:36.9999900 ってことだもんね。
いや、それは小数点以下の桁数を 7桁にして <= 2014/09/04 18:37:36.9999999 となるようにすればいいやん・・・と思うかもしれんけど、小数点以下の最大桁数って、これ、絶対固定なの?

今、仕事で使っている Windows 8.1 Pro(64bit)の VB.NET で確認すると、7桁まで取れるようなんだけど(ToString("yyyy/MM/dd HH:mm:ss.FFFFFFFF") みたいにミリ秒以下を 8桁にすると例外エラーで落ちる)、これ、32bit 版でも一緒なの?あるいは、今後 CPU のビット数や OS のバージョンが上がっても、絶対 7桁なの?12桁とかにならないの?

そのあたりが担保できない限り、やっぱミリ数は含めるべきじゃないよね。青天井で桁数増えていく可能性あるんだから。この辺、「Microsoft の勝手」の世界だよね?
今は <= 2014/09/04 18:37:36.9999999 が有効でも、何年か後はわからんってことよね。

ということで、時間は CDate(Now.ToString) して突っ込んじゃうのが一番安全そう。

「業務アプリケーション」でミリ秒まで必要なケースって糞レアだからな(笑)
そういえば、トランザクションって DB を CloseConnection した後も生きてるんだっけ?

あるフレームワークを使って VB.NET の開発をしてるんだけど、DB を参照しかしない場合も、DB への OpenConnection 後で BeginTransaction が実行される。

まあ、DB を更新をした場合は、必ず CommitTransaction か RollbackTransaction 実行して処理を抜けるんだけど、参照しかしなかった場合はその処理を書いてなかった。
というのも、処理は全て try/catch/finally 文で囲まれていて、finally で DB への CloseConnection 処理を実行してるので「DB から切断するからトランザクションも終了するわな」とか思ってた(^^;
でも、実際には終わってなくて、次に BeginTransaction した時に、「トランザクションが開始されてます」のエラーになっちゃう。

いやあ、俺がまだこのフレームワークに慣れてないのと、他にちょっと疑わしい点があったので、結局そっちの的外れな方をいろいろ調べてて、今日の午前中を無駄に過ごしてしまった(^^;

しかし、DB から切断しても Transaction って生きてるものなのね(^^;(時間が経つとタイムアウトなのかなんなのか自動で死んじゃうみたいだけど)
これまで、ずっとそんなことは意識せず生きてきたわ。
てか、自分でフルスクラッチでプログラム作る時は、参照だけの時にもトランザクションを実行するなんてことないからな(^^;

やっぱ、たまに他社のプロジェクトに入ると色々勉強になるなあ(^^;
あと、VB.NET で「え?こんな面倒なことしないといかんの?」という話だと、「バイト数での文字列の分割」かなあ。

「全角文字を途中でぶった切ってしまうことは在り得ない」という条件での処理なので、「文字列の最後が『全角文字の前半分の1byte』じゃないか?」みたいなややこしいチェックはしないでいい。だから、純粋に「byte 数で文字列を分割できる split や substr」みたいなのがあれば嬉しかったんだけど、無いのね、そんなの(^^;
ちゃんと「byte 数」じゃなく「文字数」としてアレコレ処理してくれるようで、有難迷惑だなあ(^^;

今回は、

'わたしは慎吾   00100100'
'あの子はチンコ 00001110'
'あたいは茜     00101011'

みたいなデータ(固定長)を、15byte と 8byte にぶった切りたいだけ。
例えば、「わたしは慎吾   」と「00100100」という具合に。

あれこれ試して、

Dim bytes() As Byte = System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(hogehoge)
Dim byteF() As Byte = CType(Array.CreateInstance(GetType(Byte), 15), Byte())
Dim byteR() As Byte = CType(Array.CreateInstance(GetType(Byte), 8), Byte())
Array.Copy(bytes, 0, byteF, 0, 15)  ' 1~15byte
Array.Copy(bytes, 15, byteR, 0, 8)   ' 16~23byte
Dim strF As String = System.Text.Encoding.GetEncoding("Shift_JIS").GetString(byteF)
Dim strR As String = System.Text.Encoding.GetEncoding("Shift_JIS").GetString(byteR)

※hogehoge に「わたしは慎吾   00100100」のような文字列が入っている。

とかしたんだけど、上に書いたように「全角コードを跨ぐことはない」ので「全角コードである」ということを意識する必要もないのに、なんか、Shift_JIS エンコードしてからバイト文字列に分割したりと面倒臭いことこの上無い。

もっとスマートな方法があると思うので、ぜひ、VB.NET マスターの方はコメントを!!(笑)
VB.NET の話。

最終的にソートをしたいので、DataSet から

Dim dv As DataView = ds.hoge_table.DefaultView

という具合に DataView を作成し、その中からある日時のデータ(行)だけ抜き出そうとした。
抜き出した後にソートしたいわけね。

具体的には、send_time というカラムに 2014/09/03 17:51:29 と入っている行を抜く。

そこで、

dv.RowFilter = "send_time=#" & hoge_time & "#"

としてみたが、抜き出した行数 0 なのである。(hoge_time 変数には 2014/09/03 17:51:29 という時間が DateTime 型で格納されている)

イミディエイトウィンドウで RowFilter の内容と、データを(試しに200件目のデータを)確認すると、

?dv.RowFilter.ToString
"send_time=#2014/09/03 17:51:29#"
?ds.hoge(200)(68).ToString
"2014/09/03 17:51:29"

と、どっちも 2014/09/03 17:51:29 やないけ!!?
なんで抜けんの?

・・・と少々ハマったが、どうやら DataSet に入っている日時はミリ秒まで格納されているらしい。
ToString では表示されないけど。

なので、秒までの時間でマッチングさせようとすると、

dv.RowFilter = "send_time >= #" & hoge_time.ToString & ".00000# Or send_time <= #" & hoge_time.ToString & ".99999#"

としないといけないようだ。
これで、RowFilter は、

?dv.RowFilter.ToString
"send_time >= #2014/09/03 17:51:29.00000# Or send_time <= #2014/09/03 17:51:29.99999#"

こうなって、無事マッチングした行が抜き出せたのである。

面倒くせぇ~!!(^^;

なんか、他に方法があるのかもしれないが、結局見つけ出せず。
「もっとスマートな方法があるぜ!」という .NET マスターは、ぜひここにコメントを!(笑)

このアーカイブについて

このページには、2014年9月以降に書かれたブログ記事のうちお仕事カテゴリに属しているものが含まれています。

前のアーカイブはお仕事: 2014年7月です。

次のアーカイブはお仕事: 2015年1月です。

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


月別 アーカイブ

電気ウナギ的○○ mobile ver.

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