[#44725] Set[Set[1]]==Set[Set[1]] は偽? — "5.5" <5.5@...>

5.5 です。

22 messages 2008/03/04

[#44782] $stdin.rewind が exec した子プロセスに伝わらない? — SATOH Fumiyasu <fumiyas@...>

さとうふみやす @ OSS テクノロジです。

11 messages 2008/03/17
[#44783] Re: $stdin.rewind が exec した子プロセスに伝わらない? — Kazuhiro NISHIYAMA <zn@...> 2008/03/17

西山和広です。

[ruby-list:44785] Re: $stdin.rewind が exec した子プロセスに伝わらない?

From: Nobuyoshi Nakada <nobu@...>
Date: 2008-03-17 21:14:37 UTC
List: ruby-list #44785
なかだです。

At Mon, 17 Mar 2008 20:00:58 +0900,
Kazuhiro NISHIYAMA wrote in [ruby-list:44783]:
> > $stdin.rewind したとき、その後に ruby から実行する
> > 外部コマンドに反映されないことがあるのですが、バグでしょうか?
> > 
> > $ ruby -v
> > ruby 1.8.6 (2008-03-03 patchlevel 114) [x86_64-linux]
> > 
> > $ cat stdin-rewind.rb
> > $stdin.rewind
> > system('echo -n "1: head: "; head -n 1')
> > 
> > $stdin.rewind
> > print "2: stdin.gets: ", $stdin.gets
> 
> ここの$stdin.getsで読み込んだ後の$stdin.rewindはFILE*のストリームの
> 先頭に戻る(fseek(3))だけで、ファイルディスクリプタは読み込んだ位置に
> 進んだまま(lseek(2)ではない)だから、execした後のプログラムには
> 影響しないのではないでしょうか?

stdioの実装に依存します。glibcでは、fseek(3)の結果がFILE*のバッ
ファ内に相当する場合には、lseek(2)は発行しないようです。おそらく
パフォーマンスのためでしょう。これは、rubyに限らずstdioとexecを
使えば常に発生する問題で、以下のプログラムでも再現します。

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
    FILE *f = fopen(argv[1], "r");

    if (argc > 2) fseek(f, 0L, SEEK_SET);
    fgetc(f);
    fseek(f, 0L, SEEK_SET);
    dup2(fileno(f), 0);
    system("head -1");
    return 0;
}

$ ./seektest seektest.c
#include <sys/types.h>

$ ./seektest seektest.c 1

2回目のfseek()を1Lにすると1回目のfseek()にかかわらず出力されなく
なるあたり、glibcのバグなのかもしれません。

もしかしたらもっとちゃんとした方法があるのかもしれませんが、
BUFSIZよりも大きなオフセットでfseek()することでもlseek()もされる
ようです。fflush(NULL)のようにすべてのFILE*についてseekさせるほ
うほうがあれば、before_exec()でやったほうがいいと思いますが。


Index: io.c
===================================================================
--- io.c	(revision 15790)
+++ io.c	(working copy)
@@ -674,5 +674,5 @@ rb_io_tell(io)
 }
 
-static VALUE
+static off_t
 rb_io_seek(io, offset, whence)
     VALUE io, offset;
@@ -686,7 +686,11 @@ rb_io_seek(io, offset, whence)
     pos = io_seek(fptr, pos, whence);
     if (pos < 0 && errno) rb_sys_fail(fptr->path);
+#ifdef _STDIO_USES_IOSTREAM  /* GNU libc */
+    fseeko(fptr->f, BUFSIZ * 16L, SEEK_CUR);
+    fseeko(fptr->f, pos, SEEK_SET);
+#endif
     clearerr(fptr->f);
 
-    return INT2FIX(0);
+    return pos;
 }
 
@@ -725,5 +729,6 @@ rb_io_seek_m(argc, argv, io)
     }
 
-    return rb_io_seek(io, offset, whence);
+    rb_io_seek(io, offset, whence);
+    return INT2FIX(0);
 }
 
@@ -743,13 +748,5 @@ rb_io_set_pos(io, offset)
      VALUE io, offset;
 {
-    OpenFile *fptr;
-    off_t pos;
-
-    pos = NUM2OFFT(offset);
-    GetOpenFile(io, fptr);
-    pos = io_seek(fptr, pos, SEEK_SET);
-    if (pos != 0) rb_sys_fail(fptr->path);
-    clearerr(fptr->f);
-
+    off_t pos = rb_io_seek(io, offset, SEEK_SET);
     return OFFT2NUM(pos);
 }
@@ -776,6 +773,6 @@ rb_io_rewind(io)
 
     GetOpenFile(io, fptr);
-    if (io_seek(fptr, 0L, 0) != 0) rb_sys_fail(fptr->path);
-    clearerr(fptr->f);
+    if (rb_io_seek(io, INT2FIX(0), SEEK_SET) != 0)
+	rb_sys_fail(fptr->path);
     if (io == current_file) {
 	gets_lineno -= fptr->lineno;


-- 
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
    中田 伸悦

In This Thread