OSDN Git Service

Complete open_by_handle_at.2
authorAkihiro MOTOKI <amotoki@gmail.com>
Sat, 24 Jan 2015 11:45:00 +0000 (20:45 +0900)
committerAkihiro MOTOKI <amotoki@gmail.com>
Sat, 24 Jan 2015 11:45:00 +0000 (20:45 +0900)
draft/man2/open_by_handle_at.2 [new file with mode: 0644]
po4a/stdio/po/ja.po
release/man2/open_by_handle_at.2 [new file with mode: 0644]
stats/stdio
translation_list
untrans.html

diff --git a/draft/man2/open_by_handle_at.2 b/draft/man2/open_by_handle_at.2
new file mode 100644 (file)
index 0000000..25494f3
--- /dev/null
@@ -0,0 +1,488 @@
+.\" Copyright (c) 2014 by Michael Kerrisk <mtk.manpages@gmail.com>
+.\"
+.\" %%%LICENSE_START(VERBATIM)
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one.
+.\"
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date.  The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein.  The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\"
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\" %%%LICENSE_END
+.\"
+.\"*******************************************************************
+.\"
+.\" This file was generated with po4a. Translate the source file.
+.\"
+.\"*******************************************************************
+.TH OPEN_BY_HANDLE_AT 2 2014\-06\-13 Linux "Linux Programmer's Manual"
+.SH 名前
+name_to_handle_at, open_by_handle_at \- パス名に対するハンドルの取得とハンドルによるファイルのオープン
+.SH 書式
+.nf
+\fB#define _GNU_SOURCE\fP         /* feature_test_macros(7) 参照 */
+\fB#include <sys/types.h>\fP
+\fB#include <sys/stat.h>\fP
+\fB#include <fcntl.h>\fP
+
+\fBint name_to_handle_at(int \fP\fIdirfd\fP\fB, const char *\fP\fIpathname\fP\fB,\fP
+\fB                      struct file_handle *\fP\fIhandle\fP\fB,\fP
+\fB                      int *\fP\fImount_id\fP\fB, int \fP\fIflags\fP\fB);\fP
+
+\fBint open_by_handle_at(int \fP\fImount_fd\fP\fB, struct file_handle *\fP\fIhandle\fP\fB,\fP
+\fB                      int \fP\fIflags\fP\fB);\fP
+.fi
+.SH 説明
+.\"
+.\"
+システムコール \fBname_to_handle_at\fP() と \fBopen_by_handle_at\fP() は \fBopenat\fP(2) の機能を
+2 つに分割したものである。 \fBname_to_handle_at\fP() は指定されたファイルに対応するハンドルを返す。
+\fBopen_by_handle_at\fP() は \fBname_to_handle_at\fP() が返したハンドルに対応するファイルをオープンし、
+オープンされたファイルディスクリプターを返す。
+.SS name_to_handle_at()
+\fBname_to_handle_at\fP() システムコールは、 引き数 \fIdirfd\fP と \fIpathname\fP
+で指定されるファイルに対応するファイルハンドルとマウント ID を返す。 ファイルハンドルは引き数 \fIhandle\fP で返される。 \fIhandle\fP
+は以下の形式の構造体へのポインターである。
+
+.in +4n
+.nf
+struct file_handle {
+    unsigned int  handle_bytes;   /* Size of f_handle [in, out] */
+    int           handle_type;    /* Handle type [out] */
+    unsigned char f_handle[0];    /* File identifier (sized by
+                                     caller) [out] */
+};
+.fi
+.in
+.PP
+\fIf_handle\fP で返されるハンドルを保持するのに十分な大きさの構造体を確保するのは、 呼び出し元が責任をもって行う必要がある。 呼び出し前に、
+\fIhandle_bytes\fP フィールドは \fIf_handle\fP 用に格納されたサイズで初期化すべきである
+(\fI<fcntl.h>\fP で定義されている定数 \fBMAX_HANDLE_SZ\fP でファイルハンドルの最大サイズが規定されている)。
+呼び出しが成功でリターンする際、 \fIhandle_bytes\fP フィールドは \fIf_handle\fP に実際に書き込まれたバイト数に更新される。
+
+呼び出し元では、 \fIhandle\->handle_bytes\fP を 0 に設定して呼び出しを行うことで、 \fIfile_handle\fP
+構造体に必要なサイズを知ることができる。 この場合、 この呼び出しはエラー \fBEOVERFLOW\fP で失敗し、
+\fIhandle\->handle_bytes\fP に必要なサイズが設定される。
+呼び出し元はこの情報を使って、正しいサイズの構造体を割り当てることができる (下記の「例」を参照)。
+
+\fIhandle_bytes\fP フィールドを使用する以外は、 呼び出し元は \fIfile_handle\fP 構造体の内容を意識せずに扱うべきである。
+フィールド \fIhandle_type\fP と \fIf_handle\fP は後で \fBopen_by_handle_at\fP()
+を呼び出す場合にだけ必要である。
+
+\fIflags\fP 引き数は、 下記の \fBAT_EMPTY_PATH\fP と \fBAT_SYMLINK_FOLLOW\fP のうち 0
+個以上の論理和を取って構成されるビットマスクである。
+
+引き数 \fIpathname\fP と \fIdirfd\fP はその組み合わせでハンドルを取得するファイルを指定する。 以下の 4 つのパターンがある。
+.IP * 3
+\fIpathname\fP が空でない文字列で絶対パス名を含む場合、 このパス名が参照するファイルに対するハンドルが返される。
+.IP *
+\fIpathname\fP が相対パスが入った空でない文字列で、 \fIdirfd\fP が特別な値 \fBAT_FDCWD\fP の場合、 \fIpathname\fP
+は呼び出し元のカレントワーキングディレクトリに対する相対パスと解釈され、 そのファイルに対するハンドルが返される。
+.IP *
+\fIpathname\fP が相対パスが入った空でない文字列で、 \fIdirfd\fP がディレクトリを参照するファイルディスクリプタの場合、
+\fIpathname\fP は \fIdirfd\fP が参照するディレクトリに対する相対パスと解釈され、
+そのファイルを参照するハンドルが返される。(なぜ「ディレクトリファイルディスクリプタ」が役に立つのかについては \fBopenat\fP(2) を参照。)
+.IP *
+\fIpathname\fP が空の文字列で \fIflags\fP に \fBAT_EMPTY_PATH\fP が指定されている場合、 \fIdirfd\fP
+には任意の種別のファイルを参照するオープンされたファイルディスクリプターか \fBAT_FDCWD\fP (カレントワーキングディレクトリを意味する)
+を指定でき、 \fIdirfd\fP が参照するファイルに対するハンドルが返される。
+.PP
+\fImount_id\fP 引き数は、 \fIpathname\fP に対応するファイルシステムのマウントの識別子を返す。 この識別子は
+\fI/proc/self/mountinfo\fP のいずれかのレコードの最初のフィールドに対応する。 対応するレコードの 5
+番目のフィールドのパス名をオープンすると、 このマウントポイントのファイルディスクリプターが得られる。 このファイルディスクリプターはこの後の
+\fBopen_by_handle_at\fP() の呼び出しで使用できる。
+
+デフォルトでは、 \fBname_to_handle_at\fP() は \fIpathname\fP がシンボリックリンクの場合にその展開
+(dereference) を行わず、 リンク自身に対するハンドルを返す。 \fBAT_SYMLINK_FOLLOW\fP が \fIflags\fP
+に指定されると、 \fIpathname\fP がシンボリックリンクの場合にリンクの展開が行われる (リンクが参照するファイルに対するハンドルが返される)。
+.SS open_by_handle_at()
+\fBopen_by_handle_at\fP() システムコールは \fIhandle\fP が参照するファイルをオープンする。 \fIhandle\fP は
+前に呼び出した \fBname_to_handle_at\fP() が返したファイルハンドルである。
+
+\fImount_fd\fP 引き数は、 \fIhandle\fP がそのファイルシステムに関連すると解釈されるマウントされたファイルシステム内の任意のオブジェクト
+(ファイル、 ディレクトリなど) のファイルディスクリプターである。 特別な値 \fBAT_FDCWD\fP も指定できる。
+この値は呼び出し元のカレントワーキングディレクトリを意味する。
+
+引き数 \fIflags\fP は \fBopen\fP(2) と同じである。 \fIhandle\fP がシンボリックリンクを参照している場合、 呼び出し元は
+\fBO_PATH\fP フラグを指定しなければならず、 そのシンボリックリンクは展開されない。 \fBO_NOFOLLOW\fP が指定された場合は、
+\fBO_NOFOLLOW\fP は無視される。
+
+
+\fBopen_by_handle_at\fP() を呼び出すには、 呼び出し元が \fBCAP_DAC_READ_SEARCH\fP
+ケーパビリティーを持っていなければならない。
+.SH 返り値
+成功すると、 \fBname_to_handle_at\fP() は 0 を返し、 \fBopen_by_handle_at\fP()
+は負でないファイルディスクリプターを返す。
+
+エラーの場合、 どちらのシステムコールも \-1 を返し、 \fIerrno\fP にエラーの原因を示す値を設定する。
+.SH エラー
+\fBname_to_handle_at\fP() と \fBopen_by_handle_at\fP() は \fBopenat\fP(2) と同じエラーで失敗する。
+また、 これらのシステムコールは以下のエラーで失敗することもある。
+
+\fBname_to_handle_at\fP() は以下のエラーで失敗することがある。
+.TP 
+\fBEFAULT\fP
+\fIpathname\fP, \fImount_id\fP, \fIhandle\fP のどれかがアクセス可能なアドレス空間の外を指している。
+.TP 
+\fBEINVAL\fP
+\fIflags\fP に無効なビット値が含まれている。
+.TP 
+\fBEINVAL\fP
+\fIhandle\->handle_bytes\fP が \fBMAX_HANDLE_SZ\fP よりも大きい。
+.TP 
+\fBENOENT\fP
+\fIpathname\fP が空文字列だが、 \fIflags\fP に \fBAT_EMPTY_PATH\fP がされていなかった。
+.TP 
+\fBENOTDIR\fP
+\fIdirfd\fP で指定されたファイルディスクリプターがディレクトリを参照しておらず、 両方の \fIflags\fP に \fBAT_EMPTY_PATH\fP
+が指定され、 かつ \fIpathname\fP が空文字列である場合でもない。
+.TP 
+\fBEOPNOTSUPP\fP
+ファイルシステムがパス名をファイルハンドルへの変換をサポートしていない。
+.TP 
+\fBEOVERFLOW\fP
+.\"
+.\"
+呼び出しに渡された \fIhandle\->handle_bytes\fP の値が小さすぎた。 このエラーが発生した際、
+\fIhandle\->handle_bytes\fP はハンドルに必要なサイズに更新される。
+.PP
+\fBopen_by_handle_at\fP() は以下のエラーで失敗することがある。
+.TP 
+\fBEBADF\fP
+\fImount_fd\fP がオープンされたファイルディスクリプタでない。
+.TP 
+\fBEFAULT\fP
+\fIhandle\fP がアクセス可能なアドレス空間の外を指している。
+.TP 
+\fBEINVAL\fP
+\fIhandle\->handle_bytes\fP が \fBMAX_HANDLE_SZ\fP より大きいか 0 に等しい。
+.TP 
+\fBELOOP\fP
+\fIhandle\fP がシンボリックリンクを参照しているが、 \fIflags\fP に \fBO_PATH\fP がされていなかった。
+.TP 
+\fBEPERM\fP
+呼び出し元が \fBCAP_DAC_READ_SEARCH\fP ケーパビリティを持っていない。
+.TP 
+\fBESTALE\fP
+指定された \fIhandle\fP が有効ではない。 このエラーは、 例えばファイルが削除された場合などに発生する。
+.SH バージョン
+これらのシステムコールは Linux 2.6.39 で初めて登場した。ライブラリによるサポートはバージョン 2.14 以降の glibc
+で提供されている。
+.SH 準拠
+これらのシステムコールは非標準の Linux の拡張である。
+
+FreeBSD には \fBgetfh\fP() と \fBopenfh\fP() というほとんど同じ機能のシステムコールのペアが存在する。
+.SH 注意
+あるプロセスで \fBname_to_handle_at\fP() を使ってファイルハンドルを生成して、 そのハンドルを別のプロセスの
+\fBopen_by_handle_at\fP() で使用することができる。
+
+いくつかのファイルシステムでは、 パス名からファイルハンドルへの変換がサポートされていない。 例えば、 \fI/proc\fP, \fI/sys\fP
+や種々のネットワークファイルシステムなどである。
+
+ファイルハンドルは、 ファイルが削除されたり、 その他のファイルシステム固有の理由で、 無効 ("stale") になる場合がある。
+無効なハンドルであることは、 \fBopen_by_handle_at\fP() からエラー \fBESTALE\fP が返ることで通知される。
+
+.\" https://lwn.net/Articles/375888/
+.\"    "Open by handle" - Jonathan Corbet, 2010-02-23
+これらのシステムコールは、 ユーザー空間のファイルサーバーでの使用を意図して設計されている。 例えば、 ユーザー空間 NFS
+サーバーがファイルハンドルを生成して、 そのハンドルを NFS クライアントに渡すことができる。 その後、
+クライアントがファイルをオープンしようとした際に、 このハンドルをサーバーに送り返すことができる。 このような機能により、
+ユーザー空間ファイルサーバーは、 そのサーバーが提供するファイルに関してステートレスで (状態を保持せずに) 動作することができる。
+
+.\" commit bcda76524cd1fa32af748536f27f674a13e56700
+\fIpathname\fP がシンボリックリンクを参照していて、 \fIflags\fP に \fBAT_SYMLINK_FOLLOW\fP が指定されていない場合、
+\fBname_to_handle_at\fP() は (シンボリックが参照するファイルではなく) リンクに対するハンドルを返す。
+ハンドルを受け取ったプロセスは、 \fBopen_by_handle_at\fP() の \fBO_PATH\fP
+フラグを使ってハンドルをファイルディスクリプターに変換し、 そのファイルディスクリプターを \fBreadlinkat\fP(2) や
+\fBfchownat\fP(2) などのシステムコールの \fIdirfd\fP 引き数として渡すことで、 そのシンボリックリンクに対して操作を行うことができる。
+.SS "永続的なファイルシステム ID の取得"
+\fI/proc/self/mountinfo\fP のマウント ID は、
+ファイルシステムのアンマウント、マウントが行われるに連れて再利用されることがある。 したがって、 \fBname_to_handle_at\fP() (の
+\fI*mount_id\fP) で返されたマウント ID は対応するマウントされたファイルシステムを表す永続的な ID と考えるべきではない。 ただし、
+アプリケーションは、 マウント ID に対応する  \fImountinfo\fP レコードの情報を使うことで、 永続的な ID を得ることができる。
+
+.\" e.g., http://stackoverflow.com/questions/6748429/using-libblkid-to-find-uuid-of-a-partition
+例えば、 \fImountinfo\fP レコードの 5 番目のフィールドのデバイス名を使って、 \fI/dev/disks/by\-uuid\fP
+のシンボリックリンク経由で対応するデバイス UUID を検索できる。 (UUID を取得するもっと便利な方法は \fBlibblkid\fP(3)
+ライブラリを使用することである。) そのプロセスは、逆に、 この UUID を使ってデバイス名を検索し、 対応するマウントポイントを取得することで、
+\fBopen_by_handle_at\fP() で使用する \fImount_fd\fP 引き数を生成することができる。
+.SH 例
+以下の 2 つのプログラムは \fBname_to_handle_at\fP() と \fBopen_by_handle_at\fP()
+の使用例を示したものである。 最初のプログラム (\fIt_name_to_handle_at.c\fP) は \fBname_to_handle_at\fP()
+を使用して、 コマンドライン引き数で指定されたファイルに対応するファイルハンドルとマウント ID を取得する。 ハンドルとマウント ID
+は標準出力に出力される。
+
+2 つ目のプログラム (\fIt_open_by_handle_at.c\fP) は、 標準入力からマウント ID とファイルハンドルを読み込む。 それから、
+\fBopen_by_handle_at\fP() を利用して、 そのハンドルを使ってファイルをオープンする。 追加のコマンドライン引き数が指定された場合は、
+\fBopen_by_handle_at\fP() の \fImount_fd\fP 引き数は、 この引き数で渡された名前のディレクトリをオープンして取得する。
+それ以外の場合、 \fI/proc/self/mountinfo\fP からスキャンして標準入力から読み込んだマウント ID に一致するマウント ID
+を検索し、 そのレコードで指定されているマウントディレクトリをオープンして、 \fImount_fd\fP を入手する。 (これらのプログラムではマウント
+ID が永続的ではない点についての対処は行わない。)
+
+以下のシェルセッションは、これら 2 つのプログラムの使用例である。
+
+.in +4n
+.nf
+$ \fBecho 'Can you please think about it?' > cecilia.txt\fP
+$ \fB./t_name_to_handle_at cecilia.txt > fh\fP
+$ \fB./t_open_by_handle_at < fh\fP
+open_by_handle_at: Operation not permitted
+$ \fBsudo ./t_open_by_handle_at < fh\fP      # Need CAP_SYS_ADMIN
+Read 31 bytes
+$ \fBrm cecilia.txt\fP
+.fi
+.in
+
+.\" Christoph Hellwig: That's why the file handles contain a generation
+.\" counter that gets incremented in this case.
+ここで、 ファイルを削除し (すぐに) 再作成する。 同じ内容で (運がよければ) 同じ inode になる。 この場合でも、
+\fBopen_by_handle_at\fP() はこのファイルハンドルが参照する元のファイルがすでに存在しないことを認識する。
+
+.in +4n
+.nf
+$ \fBstat \-\-printf="%i\en" cecilia.txt\fP     # Display inode number
+4072121
+$ \fBrm cecilia.txt\fP
+$ \fBecho 'Can you please think about it?' > cecilia.txt\fP
+$ \fBstat \-\-printf="%i\en" cecilia.txt\fP     # Check inode number
+4072121
+$ \fBsudo ./t_open_by_handle_at < fh\fP
+open_by_handle_at: Stale NFS file handle
+.fi
+.in
+.SS "プログラムのソース: t_name_to_handle_at.c"
+\&
+.nf
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \e
+                        } while (0)
+
+int
+main(int argc, char *argv[])
+{
+    struct file_handle *fhp;
+    int mount_id, fhsize, flags, dirfd, j;
+    char *pathname;
+
+    if (argc != 2) {
+        fprintf(stderr, "Usage: %s pathname\en", argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    pathname = argv[1];
+
+    /* file_handle 構造体を確保する */
+
+    fhsize = sizeof(*fhp);
+    fhp = malloc(fhsize);
+    if (fhp == NULL)
+        errExit("malloc");
+
+    /* name_to_handle_at() を最初に呼び出して
+       ファイルハンドルに必要なサイズを入手する */
+
+    dirfd = AT_FDCWD;           /* For name_to_handle_at() calls */
+    flags = 0;                  /* For name_to_handle_at() calls */
+    fhp\->handle_bytes = 0;
+    if (name_to_handle_at(dirfd, pathname, fhp,
+                &mount_id, flags) != \-1 || errno != EOVERFLOW) {
+        fprintf(stderr, "Unexpected result from name_to_handle_at()\en");
+        exit(EXIT_FAILURE);
+    }
+
+    /* file_handle 構造体を正しいサイズに確保し直す */
+
+    fhsize = sizeof(struct file_handle) + fhp\->handle_bytes;
+    fhp = realloc(fhp, fhsize);         /* Copies fhp\->handle_bytes */
+    if (fhp == NULL)
+        errExit("realloc");
+
+    /* コマンドラインで指定されたパス名からファイルハンドルを取得 */
+
+    if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == \-1)
+        errExit("name_to_handle_at");
+
+    /* t_open_by_handle_at.c で後で再利用できるように、マウント ID、
+       ファイルハンドルのサイズ、ファイルハンドルを標準出力に書き出す */
+
+    printf("%d\en", mount_id);
+    printf("%d %d   ", fhp\->handle_bytes, fhp\->handle_type);
+    for (j = 0; j < fhp\->handle_bytes; j++)
+        printf(" %02x", fhp\->f_handle[j]);
+    printf("\en");
+
+    exit(EXIT_SUCCESS);
+}
+.fi
+.SS "プログラムのソース: t_open_by_handle_at.c"
+\&
+.nf
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \e
+                        } while (0)
+
+/* /proc/self/mountinfo をスキャンして、マウント ID が \(aqmount_id\(aq に
+   一致する行を探す。 (もっと簡単な方法は \(aqutil\-linux\(aq プロジェクト
+   が提供する \(aqlibmount\(aq ライブラリをインストールして使うことである)
+   対応するマウントパスをオープンし、得られたファイルディスクリプターを返す。 */
+
+static int
+open_mount_path_by_id(int mount_id)
+{
+    char *linep;
+    size_t lsize;
+    char mount_path[PATH_MAX];
+    int mi_mount_id, found;
+    ssize_t nread;
+    FILE *fp;
+
+    fp = fopen("/proc/self/mountinfo", "r");
+    if (fp == NULL)
+        errExit("fopen");
+
+    found = 0;
+    linep = NULL;
+    while (!found) {
+        nread = getline(&linep, &lsize, fp);
+        if (nread == \-1)
+            break;
+
+        nread = sscanf(linep, "%d %*d %*s %*s %s",
+                       &mi_mount_id, mount_path);
+        if (nread != 2) {
+            fprintf(stderr, "Bad sscanf()\en");
+            exit(EXIT_FAILURE);
+        }
+
+        if (mi_mount_id == mount_id)
+            found = 1;
+    }
+    free(linep);
+
+    fclose(fp);
+
+    if (!found) {
+        fprintf(stderr, "Could not find mount point\en");
+        exit(EXIT_FAILURE);
+    }
+
+    return open(mount_path, O_RDONLY);
+}
+
+int
+main(int argc, char *argv[])
+{
+    struct file_handle *fhp;
+    int mount_id, fd, mount_fd, handle_bytes, j;
+    ssize_t nread;
+    char buf[1000];
+#define LINE_SIZE 100
+    char line1[LINE_SIZE], line2[LINE_SIZE];
+    char *nextp;
+
+    if ((argc > 1 && strcmp(argv[1], "\-\-help") == 0) || argc > 2) {
+        fprintf(stderr, "Usage: %s [mount\-path]\en", argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    /* マウント ID とファイルハンドル情報が入った標準入力:
+
+         Line 1: <mount_id>
+         Line 2: <handle_bytes> <handle_type>   <bytes of handle in hex>
+    */
+
+    if ((fgets(line1, sizeof(line1), stdin) == NULL) ||
+           (fgets(line2, sizeof(line2), stdin) == NULL)) {
+        fprintf(stderr, "Missing mount_id / file handle\en");
+        exit(EXIT_FAILURE);
+    }
+
+    mount_id = atoi(line1);
+
+    handle_bytes = strtoul(line2, &nextp, 0);
+
+    /* handle_bytes があれば、
+       file_handle 構造体をここで割り当てできる */
+
+    fhp = malloc(sizeof(struct file_handle) + handle_bytes);
+    if (fhp == NULL)
+        errExit("malloc");
+
+    fhp\->handle_bytes = handle_bytes;
+
+    fhp\->handle_type = strtoul(nextp, &nextp, 0);
+
+    for (j = 0; j < fhp\->handle_bytes; j++)
+        fhp\->f_handle[j] = strtoul(nextp, &nextp, 16);
+
+    /* マウントポイントのファイルディスクリプターを取得する。
+       取得は、コマンドラインで指定されたパス名をオープンするか、
+       /proc/self/mounts をスキャンして標準入力から受け取った
+       \(aqmount_id\(aq に一致するマウントを探すことで行う。 */
+
+    if (argc > 1)
+        mount_fd = open(argv[1], O_RDONLY);
+    else
+        mount_fd = open_mount_path_by_id(mount_id);
+
+    if (mount_fd == \-1)
+        errExit("opening mount fd");
+
+    /* ハンドルとマウントポイントを使ってファイルをオープンする */
+
+    fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);
+    if (fd == \-1)
+        errExit("open_by_handle_at");
+
+    /* そのファイルからバイトを読み出す */
+
+    nread = read(fd, buf, sizeof(buf));
+    if (nread == \-1)
+        errExit("read");
+
+    printf("Read %zd bytes\en", nread);
+
+    exit(EXIT_SUCCESS);
+}
+.fi
+.SH 関連項目
+\fBopen\fP(2), \fBlibblkid\fP(3), \fBblkid\fP(8), \fBfindfs\fP(8), \fBmount\fP(8)
+
+.UR https://www.kernel.org/pub/linux/utils/util\-linux/
+.UE
+で入手できる最新の
+\fIutil\-linux\fP リリースの \fIlibblkid\fP と \fIlibmount\fP のドキュメント。
+.SH この文書について
+この man ページは Linux \fIman\-pages\fP プロジェクトのリリース 3.78 の一部
+である。プロジェクトの説明とバグ報告に関する情報は
+http://www.kernel.org/doc/man\-pages/ に書かれている。
index 1ee4f0a..2dd83d3 100644 (file)
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "POT-Creation-Date: 2015-01-23 22:23+0900\n"
-"PO-Revision-Date: 2015-01-24 07:50+0900\n"
+"PO-Revision-Date: 2015-01-24 20:43+0900\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "Language: \n"
@@ -8533,7 +8533,7 @@ msgid ""
 "I<E<lt>fcntl.hE<gt>>, specifies the maximum possible size for a file "
 "handle.)  Upon successful return, the I<handle_bytes> field is updated to "
 "contain the number of bytes actually written to I<f_handle>."
-msgstr ""
+msgstr "I<f_handle> で返されるハンドルを保持するのに十分な大きさの構造体を確保するのは、 呼び出し元が責任をもって行う必要がある。 呼び出し前に、 I<handle_bytes> フィールドは I<f_handle> 用に格納されたサイズで初期化すべきである (I<E<lt>fcntl.hE<gt>> で定義されている定数 B<MAX_HANDLE_SZ> でファイルハンドルの最大サイズが規定されている)。 呼び出しが成功でリターンする際、 I<handle_bytes> フィールドは I<f_handle> に実際に書き込まれたバイト数に更新される。"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:112
@@ -8543,7 +8543,7 @@ msgid ""
 "the call fails with the error B<EOVERFLOW> and I<handle-E<gt>handle_bytes> "
 "is set to indicate the required size; the caller can then use this "
 "information to allocate a structure of the correct size (see EXAMPLE below)."
-msgstr ""
+msgstr "呼び出し元では、 I<handle-E<gt>handle_bytes> を 0 に設定して呼び出しを行うことで、 I<file_handle> 構造体に必要なサイズを知ることができる。 この場合、 この呼び出しはエラー B<EOVERFLOW> で失敗し、 I<handle-E<gt>handle_bytes> に必要なサイズが設定される。 呼び出し元はこの情報を使って、正しいサイズの構造体を割り当てることができる (下記の「例」を参照)。"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:123
@@ -8552,7 +8552,7 @@ msgid ""
 "I<file_handle> structure as an opaque data type: the I<handle_type> and "
 "I<f_handle> fields are needed only by a subsequent call to "
 "B<open_by_handle_at>()."
-msgstr ""
+msgstr "I<handle_bytes> フィールドを使用する以外は、 呼び出し元は I<file_handle> 構造体の内容を意識せずに扱うべきである。 フィールド I<handle_type> と I<f_handle> は後で B<open_by_handle_at>() を呼び出す場合にだけ必要である。"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:131
@@ -8630,7 +8630,7 @@ msgid ""
 "the records in I</proc/self/mountinfo>.  Opening the pathname in the fifth "
 "field of that record yields a file descriptor for the mount point; that file "
 "descriptor can be used in a subsequent call to B<open_by_handle_at>()."
-msgstr ""
+msgstr "I<mount_id> 引き数は、 I<pathname> に対応するファイルシステムのマウントの識別子を返す。 この識別子は I</proc/self/mountinfo> のいずれかのレコードの最初のフィールドに対応する。 対応するレコードの 5 番目のフィールドのパス名をオープンすると、 このマウントポイントのファイルディスクリプターが得られる。 このファイルディスクリプターはこの後の B<open_by_handle_at>() の呼び出しで使用できる。"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:209
@@ -8640,7 +8640,7 @@ msgid ""
 "B<AT_SYMLINK_FOLLOW> is specified in I<flags>, I<pathname> is dereferenced "
 "if it is a symbolic link (so that the call returns a handle for the file "
 "referred to by the link)."
-msgstr ""
+msgstr "デフォルトでは、 B<name_to_handle_at>() は I<pathname> がシンボリックリンクの場合にその展開 (dereference) を行わず、 リンク自身に対するハンドルを返す。 B<AT_SYMLINK_FOLLOW> が I<flags> に指定されると、 I<pathname> がシンボリックリンクの場合にリンクの展開が行われる (リンクが参照するファイルに対するハンドルが返される)。"
 
 #. type: SS
 #: build/C/man2/open_by_handle_at.2:209
@@ -8855,21 +8855,21 @@ msgstr "これらのシステムコールは非標準の Linux の拡張であ
 msgid ""
 "FreeBSD has a broadly similar pair of system calls in the form of "
 "B<getfh>()  and B<openfh>()."
-msgstr ""
+msgstr "FreeBSD には B<getfh>() と B<openfh>() というほとんど同じ機能のシステムコールのペアが存在する。"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:364
 msgid ""
 "A file handle can be generated in one process using B<name_to_handle_at>()  "
 "and later used in a different process that calls B<open_by_handle_at>()."
-msgstr ""
+msgstr "あるプロセスで B<name_to_handle_at>() を使ってファイルハンドルを生成して、 そのハンドルを別のプロセスの B<open_by_handle_at>() で使用することができる。"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:370
 msgid ""
 "Some filesystem don't support the translation of pathnames to file handles, "
 "for example, I</proc>, I</sys>, and various network filesystems."
-msgstr ""
+msgstr "いくつかのファイルシステムでは、 パス名からファイルハンドルへの変換がサポートされていない。 例えば、 I</proc>, I</sys> や種々のネットワークファイルシステムなどである。"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:377
@@ -8877,7 +8877,7 @@ msgid ""
 "A file handle may become invalid (\"stale\") if a file is deleted, or for "
 "other filesystem-specific reasons.  Invalid handles are notified by an "
 "B<ESTALE> error from B<open_by_handle_at>()."
-msgstr ""
+msgstr "ファイルハンドルは、 ファイルが削除されたり、 その他のファイルシステム固有の理由で、 無効 (\"stale\") になる場合がある。 無効なハンドルであることは、 B<open_by_handle_at>() からエラー B<ESTALE> が返ることで通知される。"
 
 #.  https://lwn.net/Articles/375888/
 #.     "Open by handle" - Jonathan Corbet, 2010-02-23
@@ -8890,7 +8890,7 @@ msgid ""
 "the handle back to the server.  This sort of functionality allows a user-"
 "space file server to operate in a stateless fashion with respect to the "
 "files it serves."
-msgstr ""
+msgstr "これらのシステムコールは、 ユーザー空間のファイルサーバーでの使用を意図して設計されている。 例えば、 ユーザー空間 NFS サーバーがファイルハンドルを生成して、 そのハンドルを NFS クライアントに渡すことができる。 その後、 クライアントがファイルをオープンしようとした際に、 このハンドルをサーバーに送り返すことができる。 このような機能により、 ユーザー空間ファイルサーバーは、 そのサーバーが提供するファイルに関してステートレスで (状態を保持せずに) 動作することができる。"
 
 #.  commit bcda76524cd1fa32af748536f27f674a13e56700
 #. type: Plain text
@@ -8903,13 +8903,13 @@ msgid ""
 "handle to a file descriptor using B<open_by_handle_at>()  with the B<O_PATH> "
 "flag, and then passing the file descriptor as the I<dirfd> argument in "
 "system calls such as B<readlinkat>(2)  and B<fchownat>(2)."
-msgstr ""
+msgstr "I<pathname> がシンボリックリンクを参照していて、 I<flags> に B<AT_SYMLINK_FOLLOW> が指定されていない場合、 B<name_to_handle_at>() は (シンボリックが参照するファイルではなく) リンクに対するハンドルを返す。 ハンドルを受け取ったプロセスは、 B<open_by_handle_at>() の B<O_PATH> フラグを使ってハンドルをファイルディスクリプターに変換し、 そのファイルディスクリプターを B<readlinkat>(2) や B<fchownat>(2) などのシステムコールの I<dirfd> 引き数として渡すことで、 そのシンボリックリンクに対して操作を行うことができる。"
 
 #. type: SS
 #: build/C/man2/open_by_handle_at.2:409
 #, no-wrap
 msgid "Obtaining a persistent filesystem ID"
-msgstr ""
+msgstr "永続的なファイルシステム ID の取得"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:423
@@ -8920,7 +8920,7 @@ msgid ""
 "persistent identifier for the corresponding mounted filesystem.  However, an "
 "application can use the information in the I<mountinfo> record that "
 "corresponds to the mount ID to derive a persistent identifier."
-msgstr ""
+msgstr "I</proc/self/mountinfo> のマウント ID は、 ファイルシステムのアンマウント、マウントが行われるに連れて再利用されることがある。 したがって、 B<name_to_handle_at>() (の I<*mount_id>) で返されたマウント ID は対応するマウントされたファイルシステムを表す永続的な ID と考えるべきではない。 ただし、 アプリケーションは、 マウント ID に対応する  I<mountinfo> レコードの情報を使うことで、 永続的な ID を得ることができる。"
 
 #.  e.g., http://stackoverflow.com/questions/6748429/using-libblkid-to-find-uuid-of-a-partition
 #. type: Plain text
@@ -8933,7 +8933,7 @@ msgid ""
 "then be reversed, using the UUID to look up the device name, and then "
 "obtaining the corresponding mount point, in order to produce the I<mount_fd> "
 "argument used by B<open_by_handle_at>()."
-msgstr ""
+msgstr "例えば、 I<mountinfo> レコードの 5 番目のフィールドのデバイス名を使って、 I</dev/disks/by-uuid> のシンボリックリンク経由で対応するデバイス UUID を検索できる。 (UUID を取得するもっと便利な方法は B<libblkid>(3) ライブラリを使用することである。) そのプロセスは、逆に、 この UUID を使ってデバイス名を検索し、 対応するマウントポイントを取得することで、 B<open_by_handle_at>() で使用する I<mount_fd> 引き数を生成することができる。"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:451
@@ -8962,7 +8962,7 @@ msgid ""
 "mountinfo> to find a record whose mount ID matches the mount ID read from "
 "standard input, and the mount directory specified in that record is opened.  "
 "(These programs do not deal with the fact that mount IDs are not persistent.)"
-msgstr ""
+msgstr "2 つ目のプログラム (I<t_open_by_handle_at.c>) は、 標準入力からマウント ID とファイルハンドルを読み込む。 それから、 B<open_by_handle_at>() を利用して、 そのハンドルを使ってファイルをオープンする。 追加のコマンドライン引き数が指定された場合は、 B<open_by_handle_at>() の I<mount_fd> 引き数は、 この引き数で渡された名前のディレクトリをオープンして取得する。 それ以外の場合、 I</proc/self/mountinfo> からスキャンして標準入力から読み込んだマウント ID に一致するマウント ID を検索し、 そのレコードで指定されているマウントディレクトリをオープンして、 I<mount_fd> を入手する。 (これらのプログラムではマウント ID が永続的ではない点についての対処は行わない。)"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:473
@@ -8998,7 +8998,7 @@ msgid ""
 "content and (by chance) the same inode.  Nevertheless, "
 "B<open_by_handle_at>()  recognizes that the original file referred to by the "
 "file handle no longer exists."
-msgstr ""
+msgstr "ここで、 ファイルを削除し (すぐに) 再作成する。 同じ内容で (運がよければ) 同じ inode になる。 この場合でも、 B<open_by_handle_at>() はこのファイルハンドルが参照する元のファイルがすでに存在しないことを認識する。"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:505
@@ -9104,7 +9104,7 @@ msgstr "    pathname = argv[1];\n"
 #: build/C/man2/open_by_handle_at.2:538
 #, no-wrap
 msgid "    /* Allocate file_handle structure */\n"
-msgstr "    /* Allocate file_handle structure */\n"
+msgstr "    /* file_handle 構造体を確保する */\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:543
@@ -9127,8 +9127,8 @@ msgid ""
 "    /* Make an initial call to name_to_handle_at() to discover\n"
 "       the size required for file handle */\n"
 msgstr ""
-"    /* Make an initial call to name_to_handle_at() to discover\n"
-"       the size required for file handle */\n"
+"    /* name_to_handle_at() を最初に呼び出して\n"
+"       ファイルハンドルに必要なサイズを入手する */\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:555
@@ -9156,7 +9156,7 @@ msgstr ""
 #: build/C/man2/open_by_handle_at.2:557
 #, no-wrap
 msgid "    /* Reallocate file_handle structure with correct size */\n"
-msgstr "    /* Reallocate file_handle structure with correct size */\n"
+msgstr "    /* file_handle 構造体を正しいサイズに確保し直す */\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:562
@@ -9176,7 +9176,7 @@ msgstr ""
 #: build/C/man2/open_by_handle_at.2:564
 #, no-wrap
 msgid "    /* Get file handle from pathname supplied on command line */\n"
-msgstr "    /* Get file handle from pathname supplied on command line */\n"
+msgstr "    /* コマンドラインで指定されたパス名からファイルハンドルを取得 */\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:567
@@ -9195,8 +9195,8 @@ msgid ""
 "    /* Write mount ID, file handle size, and file handle to stdout,\n"
 "       for later reuse by t_open_by_handle_at.c */\n"
 msgstr ""
-"    /* Write mount ID, file handle size, and file handle to stdout,\n"
-"       for later reuse by t_open_by_handle_at.c */\n"
+"    /* t_open_by_handle_at.c で後で再利用できるように、マウント ID、\n"
+"       ファイルハンドルのサイズ、ファイルハンドルを標準出力に書き出す */\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:576
@@ -9254,11 +9254,10 @@ msgid ""
 "   Open the corresponding mount path and return the resulting file\n"
 "   descriptor. */\n"
 msgstr ""
-"/* Scan /proc/self/mountinfo to find the line whose mount ID matches\n"
-"   \\(aqmount_id\\(aq. (An easier way to do this is to install and use the\n"
-"   \\(aqlibmount\\(aq library provided by the \\(aqutil-linux\\(aq project.)\n"
-"   Open the corresponding mount path and return the resulting file\n"
-"   descriptor. */\n"
+"/* /proc/self/mountinfo をスキャンして、マウント ID が \\(aqmount_id\\(aq に\n"
+"   一致する行を探す。 (もっと簡単な方法は \\(aqutil-linux\\(aq プロジェクト\n"
+"   が提供する \\(aqlibmount\\(aq ライブラリをインストールして使うことである)\n"
+"   対応するマウントパスをオープンし、得られたファイルディスクリプターを返す。 */\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:611
@@ -9420,7 +9419,7 @@ msgstr ""
 #: build/C/man2/open_by_handle_at.2:662
 #, no-wrap
 msgid "    /* Standard input contains mount ID and file handle information:\n"
-msgstr "    /* Standard input contains mount ID and file handle information:\n"
+msgstr "    /* マウント ID とファイルハンドル情報が入った標準入力:\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:666
@@ -9466,7 +9465,9 @@ msgstr "    handle_bytes = strtoul(line2, &nextp, 0);\n"
 #: build/C/man2/open_by_handle_at.2:678
 #, no-wrap
 msgid "    /* Given handle_bytes, we can now allocate file_handle structure */\n"
-msgstr "    /* Given handle_bytes, we can now allocate file_handle structure */\n"
+msgstr ""
+"    /* handle_bytes があれば、\n"
+"       file_handle 構造体をここで割り当てできる */\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:682
@@ -9511,10 +9512,10 @@ msgid ""
 "       /proc/self/mounts to find a mount that matches the \\(aqmount_id\\(aq\n"
 "       that we received from stdin. */\n"
 msgstr ""
-"    /* Obtain file descriptor for mount point, either by opening\n"
-"       the pathname specified on the command line, or by scanning\n"
-"       /proc/self/mounts to find a mount that matches the \\(aqmount_id\\(aq\n"
-"       that we received from stdin. */\n"
+"    /* マウントポイントのファイルディスクリプターを取得する。\n"
+"       取得は、コマンドラインで指定されたパス名をオープンするか、\n"
+"       /proc/self/mounts をスキャンして標準入力から受け取った\n"
+"       \\(aqmount_id\\(aq に一致するマウントを探すことで行う。 */\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:699
@@ -9544,7 +9545,7 @@ msgstr ""
 #: build/C/man2/open_by_handle_at.2:704
 #, no-wrap
 msgid "    /* Open file using handle and mount point */\n"
-msgstr "    /* Open file using handle and mount point */\n"
+msgstr "    /* ハンドルとマウントポイントを使ってファイルをオープンする */\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:708
@@ -9562,7 +9563,7 @@ msgstr ""
 #: build/C/man2/open_by_handle_at.2:710
 #, no-wrap
 msgid "    /* Try reading a few bytes from the file */\n"
-msgstr "    /* Try reading a few bytes from the file */\n"
+msgstr "    /* そのファイルからバイトを読み出す */\n"
 
 #. type: Plain text
 #: build/C/man2/open_by_handle_at.2:714
diff --git a/release/man2/open_by_handle_at.2 b/release/man2/open_by_handle_at.2
new file mode 100644 (file)
index 0000000..25494f3
--- /dev/null
@@ -0,0 +1,488 @@
+.\" Copyright (c) 2014 by Michael Kerrisk <mtk.manpages@gmail.com>
+.\"
+.\" %%%LICENSE_START(VERBATIM)
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one.
+.\"
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date.  The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein.  The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\"
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\" %%%LICENSE_END
+.\"
+.\"*******************************************************************
+.\"
+.\" This file was generated with po4a. Translate the source file.
+.\"
+.\"*******************************************************************
+.TH OPEN_BY_HANDLE_AT 2 2014\-06\-13 Linux "Linux Programmer's Manual"
+.SH 名前
+name_to_handle_at, open_by_handle_at \- パス名に対するハンドルの取得とハンドルによるファイルのオープン
+.SH 書式
+.nf
+\fB#define _GNU_SOURCE\fP         /* feature_test_macros(7) 参照 */
+\fB#include <sys/types.h>\fP
+\fB#include <sys/stat.h>\fP
+\fB#include <fcntl.h>\fP
+
+\fBint name_to_handle_at(int \fP\fIdirfd\fP\fB, const char *\fP\fIpathname\fP\fB,\fP
+\fB                      struct file_handle *\fP\fIhandle\fP\fB,\fP
+\fB                      int *\fP\fImount_id\fP\fB, int \fP\fIflags\fP\fB);\fP
+
+\fBint open_by_handle_at(int \fP\fImount_fd\fP\fB, struct file_handle *\fP\fIhandle\fP\fB,\fP
+\fB                      int \fP\fIflags\fP\fB);\fP
+.fi
+.SH 説明
+.\"
+.\"
+システムコール \fBname_to_handle_at\fP() と \fBopen_by_handle_at\fP() は \fBopenat\fP(2) の機能を
+2 つに分割したものである。 \fBname_to_handle_at\fP() は指定されたファイルに対応するハンドルを返す。
+\fBopen_by_handle_at\fP() は \fBname_to_handle_at\fP() が返したハンドルに対応するファイルをオープンし、
+オープンされたファイルディスクリプターを返す。
+.SS name_to_handle_at()
+\fBname_to_handle_at\fP() システムコールは、 引き数 \fIdirfd\fP と \fIpathname\fP
+で指定されるファイルに対応するファイルハンドルとマウント ID を返す。 ファイルハンドルは引き数 \fIhandle\fP で返される。 \fIhandle\fP
+は以下の形式の構造体へのポインターである。
+
+.in +4n
+.nf
+struct file_handle {
+    unsigned int  handle_bytes;   /* Size of f_handle [in, out] */
+    int           handle_type;    /* Handle type [out] */
+    unsigned char f_handle[0];    /* File identifier (sized by
+                                     caller) [out] */
+};
+.fi
+.in
+.PP
+\fIf_handle\fP で返されるハンドルを保持するのに十分な大きさの構造体を確保するのは、 呼び出し元が責任をもって行う必要がある。 呼び出し前に、
+\fIhandle_bytes\fP フィールドは \fIf_handle\fP 用に格納されたサイズで初期化すべきである
+(\fI<fcntl.h>\fP で定義されている定数 \fBMAX_HANDLE_SZ\fP でファイルハンドルの最大サイズが規定されている)。
+呼び出しが成功でリターンする際、 \fIhandle_bytes\fP フィールドは \fIf_handle\fP に実際に書き込まれたバイト数に更新される。
+
+呼び出し元では、 \fIhandle\->handle_bytes\fP を 0 に設定して呼び出しを行うことで、 \fIfile_handle\fP
+構造体に必要なサイズを知ることができる。 この場合、 この呼び出しはエラー \fBEOVERFLOW\fP で失敗し、
+\fIhandle\->handle_bytes\fP に必要なサイズが設定される。
+呼び出し元はこの情報を使って、正しいサイズの構造体を割り当てることができる (下記の「例」を参照)。
+
+\fIhandle_bytes\fP フィールドを使用する以外は、 呼び出し元は \fIfile_handle\fP 構造体の内容を意識せずに扱うべきである。
+フィールド \fIhandle_type\fP と \fIf_handle\fP は後で \fBopen_by_handle_at\fP()
+を呼び出す場合にだけ必要である。
+
+\fIflags\fP 引き数は、 下記の \fBAT_EMPTY_PATH\fP と \fBAT_SYMLINK_FOLLOW\fP のうち 0
+個以上の論理和を取って構成されるビットマスクである。
+
+引き数 \fIpathname\fP と \fIdirfd\fP はその組み合わせでハンドルを取得するファイルを指定する。 以下の 4 つのパターンがある。
+.IP * 3
+\fIpathname\fP が空でない文字列で絶対パス名を含む場合、 このパス名が参照するファイルに対するハンドルが返される。
+.IP *
+\fIpathname\fP が相対パスが入った空でない文字列で、 \fIdirfd\fP が特別な値 \fBAT_FDCWD\fP の場合、 \fIpathname\fP
+は呼び出し元のカレントワーキングディレクトリに対する相対パスと解釈され、 そのファイルに対するハンドルが返される。
+.IP *
+\fIpathname\fP が相対パスが入った空でない文字列で、 \fIdirfd\fP がディレクトリを参照するファイルディスクリプタの場合、
+\fIpathname\fP は \fIdirfd\fP が参照するディレクトリに対する相対パスと解釈され、
+そのファイルを参照するハンドルが返される。(なぜ「ディレクトリファイルディスクリプタ」が役に立つのかについては \fBopenat\fP(2) を参照。)
+.IP *
+\fIpathname\fP が空の文字列で \fIflags\fP に \fBAT_EMPTY_PATH\fP が指定されている場合、 \fIdirfd\fP
+には任意の種別のファイルを参照するオープンされたファイルディスクリプターか \fBAT_FDCWD\fP (カレントワーキングディレクトリを意味する)
+を指定でき、 \fIdirfd\fP が参照するファイルに対するハンドルが返される。
+.PP
+\fImount_id\fP 引き数は、 \fIpathname\fP に対応するファイルシステムのマウントの識別子を返す。 この識別子は
+\fI/proc/self/mountinfo\fP のいずれかのレコードの最初のフィールドに対応する。 対応するレコードの 5
+番目のフィールドのパス名をオープンすると、 このマウントポイントのファイルディスクリプターが得られる。 このファイルディスクリプターはこの後の
+\fBopen_by_handle_at\fP() の呼び出しで使用できる。
+
+デフォルトでは、 \fBname_to_handle_at\fP() は \fIpathname\fP がシンボリックリンクの場合にその展開
+(dereference) を行わず、 リンク自身に対するハンドルを返す。 \fBAT_SYMLINK_FOLLOW\fP が \fIflags\fP
+に指定されると、 \fIpathname\fP がシンボリックリンクの場合にリンクの展開が行われる (リンクが参照するファイルに対するハンドルが返される)。
+.SS open_by_handle_at()
+\fBopen_by_handle_at\fP() システムコールは \fIhandle\fP が参照するファイルをオープンする。 \fIhandle\fP は
+前に呼び出した \fBname_to_handle_at\fP() が返したファイルハンドルである。
+
+\fImount_fd\fP 引き数は、 \fIhandle\fP がそのファイルシステムに関連すると解釈されるマウントされたファイルシステム内の任意のオブジェクト
+(ファイル、 ディレクトリなど) のファイルディスクリプターである。 特別な値 \fBAT_FDCWD\fP も指定できる。
+この値は呼び出し元のカレントワーキングディレクトリを意味する。
+
+引き数 \fIflags\fP は \fBopen\fP(2) と同じである。 \fIhandle\fP がシンボリックリンクを参照している場合、 呼び出し元は
+\fBO_PATH\fP フラグを指定しなければならず、 そのシンボリックリンクは展開されない。 \fBO_NOFOLLOW\fP が指定された場合は、
+\fBO_NOFOLLOW\fP は無視される。
+
+
+\fBopen_by_handle_at\fP() を呼び出すには、 呼び出し元が \fBCAP_DAC_READ_SEARCH\fP
+ケーパビリティーを持っていなければならない。
+.SH 返り値
+成功すると、 \fBname_to_handle_at\fP() は 0 を返し、 \fBopen_by_handle_at\fP()
+は負でないファイルディスクリプターを返す。
+
+エラーの場合、 どちらのシステムコールも \-1 を返し、 \fIerrno\fP にエラーの原因を示す値を設定する。
+.SH エラー
+\fBname_to_handle_at\fP() と \fBopen_by_handle_at\fP() は \fBopenat\fP(2) と同じエラーで失敗する。
+また、 これらのシステムコールは以下のエラーで失敗することもある。
+
+\fBname_to_handle_at\fP() は以下のエラーで失敗することがある。
+.TP 
+\fBEFAULT\fP
+\fIpathname\fP, \fImount_id\fP, \fIhandle\fP のどれかがアクセス可能なアドレス空間の外を指している。
+.TP 
+\fBEINVAL\fP
+\fIflags\fP に無効なビット値が含まれている。
+.TP 
+\fBEINVAL\fP
+\fIhandle\->handle_bytes\fP が \fBMAX_HANDLE_SZ\fP よりも大きい。
+.TP 
+\fBENOENT\fP
+\fIpathname\fP が空文字列だが、 \fIflags\fP に \fBAT_EMPTY_PATH\fP がされていなかった。
+.TP 
+\fBENOTDIR\fP
+\fIdirfd\fP で指定されたファイルディスクリプターがディレクトリを参照しておらず、 両方の \fIflags\fP に \fBAT_EMPTY_PATH\fP
+が指定され、 かつ \fIpathname\fP が空文字列である場合でもない。
+.TP 
+\fBEOPNOTSUPP\fP
+ファイルシステムがパス名をファイルハンドルへの変換をサポートしていない。
+.TP 
+\fBEOVERFLOW\fP
+.\"
+.\"
+呼び出しに渡された \fIhandle\->handle_bytes\fP の値が小さすぎた。 このエラーが発生した際、
+\fIhandle\->handle_bytes\fP はハンドルに必要なサイズに更新される。
+.PP
+\fBopen_by_handle_at\fP() は以下のエラーで失敗することがある。
+.TP 
+\fBEBADF\fP
+\fImount_fd\fP がオープンされたファイルディスクリプタでない。
+.TP 
+\fBEFAULT\fP
+\fIhandle\fP がアクセス可能なアドレス空間の外を指している。
+.TP 
+\fBEINVAL\fP
+\fIhandle\->handle_bytes\fP が \fBMAX_HANDLE_SZ\fP より大きいか 0 に等しい。
+.TP 
+\fBELOOP\fP
+\fIhandle\fP がシンボリックリンクを参照しているが、 \fIflags\fP に \fBO_PATH\fP がされていなかった。
+.TP 
+\fBEPERM\fP
+呼び出し元が \fBCAP_DAC_READ_SEARCH\fP ケーパビリティを持っていない。
+.TP 
+\fBESTALE\fP
+指定された \fIhandle\fP が有効ではない。 このエラーは、 例えばファイルが削除された場合などに発生する。
+.SH バージョン
+これらのシステムコールは Linux 2.6.39 で初めて登場した。ライブラリによるサポートはバージョン 2.14 以降の glibc
+で提供されている。
+.SH 準拠
+これらのシステムコールは非標準の Linux の拡張である。
+
+FreeBSD には \fBgetfh\fP() と \fBopenfh\fP() というほとんど同じ機能のシステムコールのペアが存在する。
+.SH 注意
+あるプロセスで \fBname_to_handle_at\fP() を使ってファイルハンドルを生成して、 そのハンドルを別のプロセスの
+\fBopen_by_handle_at\fP() で使用することができる。
+
+いくつかのファイルシステムでは、 パス名からファイルハンドルへの変換がサポートされていない。 例えば、 \fI/proc\fP, \fI/sys\fP
+や種々のネットワークファイルシステムなどである。
+
+ファイルハンドルは、 ファイルが削除されたり、 その他のファイルシステム固有の理由で、 無効 ("stale") になる場合がある。
+無効なハンドルであることは、 \fBopen_by_handle_at\fP() からエラー \fBESTALE\fP が返ることで通知される。
+
+.\" https://lwn.net/Articles/375888/
+.\"    "Open by handle" - Jonathan Corbet, 2010-02-23
+これらのシステムコールは、 ユーザー空間のファイルサーバーでの使用を意図して設計されている。 例えば、 ユーザー空間 NFS
+サーバーがファイルハンドルを生成して、 そのハンドルを NFS クライアントに渡すことができる。 その後、
+クライアントがファイルをオープンしようとした際に、 このハンドルをサーバーに送り返すことができる。 このような機能により、
+ユーザー空間ファイルサーバーは、 そのサーバーが提供するファイルに関してステートレスで (状態を保持せずに) 動作することができる。
+
+.\" commit bcda76524cd1fa32af748536f27f674a13e56700
+\fIpathname\fP がシンボリックリンクを参照していて、 \fIflags\fP に \fBAT_SYMLINK_FOLLOW\fP が指定されていない場合、
+\fBname_to_handle_at\fP() は (シンボリックが参照するファイルではなく) リンクに対するハンドルを返す。
+ハンドルを受け取ったプロセスは、 \fBopen_by_handle_at\fP() の \fBO_PATH\fP
+フラグを使ってハンドルをファイルディスクリプターに変換し、 そのファイルディスクリプターを \fBreadlinkat\fP(2) や
+\fBfchownat\fP(2) などのシステムコールの \fIdirfd\fP 引き数として渡すことで、 そのシンボリックリンクに対して操作を行うことができる。
+.SS "永続的なファイルシステム ID の取得"
+\fI/proc/self/mountinfo\fP のマウント ID は、
+ファイルシステムのアンマウント、マウントが行われるに連れて再利用されることがある。 したがって、 \fBname_to_handle_at\fP() (の
+\fI*mount_id\fP) で返されたマウント ID は対応するマウントされたファイルシステムを表す永続的な ID と考えるべきではない。 ただし、
+アプリケーションは、 マウント ID に対応する  \fImountinfo\fP レコードの情報を使うことで、 永続的な ID を得ることができる。
+
+.\" e.g., http://stackoverflow.com/questions/6748429/using-libblkid-to-find-uuid-of-a-partition
+例えば、 \fImountinfo\fP レコードの 5 番目のフィールドのデバイス名を使って、 \fI/dev/disks/by\-uuid\fP
+のシンボリックリンク経由で対応するデバイス UUID を検索できる。 (UUID を取得するもっと便利な方法は \fBlibblkid\fP(3)
+ライブラリを使用することである。) そのプロセスは、逆に、 この UUID を使ってデバイス名を検索し、 対応するマウントポイントを取得することで、
+\fBopen_by_handle_at\fP() で使用する \fImount_fd\fP 引き数を生成することができる。
+.SH 例
+以下の 2 つのプログラムは \fBname_to_handle_at\fP() と \fBopen_by_handle_at\fP()
+の使用例を示したものである。 最初のプログラム (\fIt_name_to_handle_at.c\fP) は \fBname_to_handle_at\fP()
+を使用して、 コマンドライン引き数で指定されたファイルに対応するファイルハンドルとマウント ID を取得する。 ハンドルとマウント ID
+は標準出力に出力される。
+
+2 つ目のプログラム (\fIt_open_by_handle_at.c\fP) は、 標準入力からマウント ID とファイルハンドルを読み込む。 それから、
+\fBopen_by_handle_at\fP() を利用して、 そのハンドルを使ってファイルをオープンする。 追加のコマンドライン引き数が指定された場合は、
+\fBopen_by_handle_at\fP() の \fImount_fd\fP 引き数は、 この引き数で渡された名前のディレクトリをオープンして取得する。
+それ以外の場合、 \fI/proc/self/mountinfo\fP からスキャンして標準入力から読み込んだマウント ID に一致するマウント ID
+を検索し、 そのレコードで指定されているマウントディレクトリをオープンして、 \fImount_fd\fP を入手する。 (これらのプログラムではマウント
+ID が永続的ではない点についての対処は行わない。)
+
+以下のシェルセッションは、これら 2 つのプログラムの使用例である。
+
+.in +4n
+.nf
+$ \fBecho 'Can you please think about it?' > cecilia.txt\fP
+$ \fB./t_name_to_handle_at cecilia.txt > fh\fP
+$ \fB./t_open_by_handle_at < fh\fP
+open_by_handle_at: Operation not permitted
+$ \fBsudo ./t_open_by_handle_at < fh\fP      # Need CAP_SYS_ADMIN
+Read 31 bytes
+$ \fBrm cecilia.txt\fP
+.fi
+.in
+
+.\" Christoph Hellwig: That's why the file handles contain a generation
+.\" counter that gets incremented in this case.
+ここで、 ファイルを削除し (すぐに) 再作成する。 同じ内容で (運がよければ) 同じ inode になる。 この場合でも、
+\fBopen_by_handle_at\fP() はこのファイルハンドルが参照する元のファイルがすでに存在しないことを認識する。
+
+.in +4n
+.nf
+$ \fBstat \-\-printf="%i\en" cecilia.txt\fP     # Display inode number
+4072121
+$ \fBrm cecilia.txt\fP
+$ \fBecho 'Can you please think about it?' > cecilia.txt\fP
+$ \fBstat \-\-printf="%i\en" cecilia.txt\fP     # Check inode number
+4072121
+$ \fBsudo ./t_open_by_handle_at < fh\fP
+open_by_handle_at: Stale NFS file handle
+.fi
+.in
+.SS "プログラムのソース: t_name_to_handle_at.c"
+\&
+.nf
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \e
+                        } while (0)
+
+int
+main(int argc, char *argv[])
+{
+    struct file_handle *fhp;
+    int mount_id, fhsize, flags, dirfd, j;
+    char *pathname;
+
+    if (argc != 2) {
+        fprintf(stderr, "Usage: %s pathname\en", argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    pathname = argv[1];
+
+    /* file_handle 構造体を確保する */
+
+    fhsize = sizeof(*fhp);
+    fhp = malloc(fhsize);
+    if (fhp == NULL)
+        errExit("malloc");
+
+    /* name_to_handle_at() を最初に呼び出して
+       ファイルハンドルに必要なサイズを入手する */
+
+    dirfd = AT_FDCWD;           /* For name_to_handle_at() calls */
+    flags = 0;                  /* For name_to_handle_at() calls */
+    fhp\->handle_bytes = 0;
+    if (name_to_handle_at(dirfd, pathname, fhp,
+                &mount_id, flags) != \-1 || errno != EOVERFLOW) {
+        fprintf(stderr, "Unexpected result from name_to_handle_at()\en");
+        exit(EXIT_FAILURE);
+    }
+
+    /* file_handle 構造体を正しいサイズに確保し直す */
+
+    fhsize = sizeof(struct file_handle) + fhp\->handle_bytes;
+    fhp = realloc(fhp, fhsize);         /* Copies fhp\->handle_bytes */
+    if (fhp == NULL)
+        errExit("realloc");
+
+    /* コマンドラインで指定されたパス名からファイルハンドルを取得 */
+
+    if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == \-1)
+        errExit("name_to_handle_at");
+
+    /* t_open_by_handle_at.c で後で再利用できるように、マウント ID、
+       ファイルハンドルのサイズ、ファイルハンドルを標準出力に書き出す */
+
+    printf("%d\en", mount_id);
+    printf("%d %d   ", fhp\->handle_bytes, fhp\->handle_type);
+    for (j = 0; j < fhp\->handle_bytes; j++)
+        printf(" %02x", fhp\->f_handle[j]);
+    printf("\en");
+
+    exit(EXIT_SUCCESS);
+}
+.fi
+.SS "プログラムのソース: t_open_by_handle_at.c"
+\&
+.nf
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \e
+                        } while (0)
+
+/* /proc/self/mountinfo をスキャンして、マウント ID が \(aqmount_id\(aq に
+   一致する行を探す。 (もっと簡単な方法は \(aqutil\-linux\(aq プロジェクト
+   が提供する \(aqlibmount\(aq ライブラリをインストールして使うことである)
+   対応するマウントパスをオープンし、得られたファイルディスクリプターを返す。 */
+
+static int
+open_mount_path_by_id(int mount_id)
+{
+    char *linep;
+    size_t lsize;
+    char mount_path[PATH_MAX];
+    int mi_mount_id, found;
+    ssize_t nread;
+    FILE *fp;
+
+    fp = fopen("/proc/self/mountinfo", "r");
+    if (fp == NULL)
+        errExit("fopen");
+
+    found = 0;
+    linep = NULL;
+    while (!found) {
+        nread = getline(&linep, &lsize, fp);
+        if (nread == \-1)
+            break;
+
+        nread = sscanf(linep, "%d %*d %*s %*s %s",
+                       &mi_mount_id, mount_path);
+        if (nread != 2) {
+            fprintf(stderr, "Bad sscanf()\en");
+            exit(EXIT_FAILURE);
+        }
+
+        if (mi_mount_id == mount_id)
+            found = 1;
+    }
+    free(linep);
+
+    fclose(fp);
+
+    if (!found) {
+        fprintf(stderr, "Could not find mount point\en");
+        exit(EXIT_FAILURE);
+    }
+
+    return open(mount_path, O_RDONLY);
+}
+
+int
+main(int argc, char *argv[])
+{
+    struct file_handle *fhp;
+    int mount_id, fd, mount_fd, handle_bytes, j;
+    ssize_t nread;
+    char buf[1000];
+#define LINE_SIZE 100
+    char line1[LINE_SIZE], line2[LINE_SIZE];
+    char *nextp;
+
+    if ((argc > 1 && strcmp(argv[1], "\-\-help") == 0) || argc > 2) {
+        fprintf(stderr, "Usage: %s [mount\-path]\en", argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    /* マウント ID とファイルハンドル情報が入った標準入力:
+
+         Line 1: <mount_id>
+         Line 2: <handle_bytes> <handle_type>   <bytes of handle in hex>
+    */
+
+    if ((fgets(line1, sizeof(line1), stdin) == NULL) ||
+           (fgets(line2, sizeof(line2), stdin) == NULL)) {
+        fprintf(stderr, "Missing mount_id / file handle\en");
+        exit(EXIT_FAILURE);
+    }
+
+    mount_id = atoi(line1);
+
+    handle_bytes = strtoul(line2, &nextp, 0);
+
+    /* handle_bytes があれば、
+       file_handle 構造体をここで割り当てできる */
+
+    fhp = malloc(sizeof(struct file_handle) + handle_bytes);
+    if (fhp == NULL)
+        errExit("malloc");
+
+    fhp\->handle_bytes = handle_bytes;
+
+    fhp\->handle_type = strtoul(nextp, &nextp, 0);
+
+    for (j = 0; j < fhp\->handle_bytes; j++)
+        fhp\->f_handle[j] = strtoul(nextp, &nextp, 16);
+
+    /* マウントポイントのファイルディスクリプターを取得する。
+       取得は、コマンドラインで指定されたパス名をオープンするか、
+       /proc/self/mounts をスキャンして標準入力から受け取った
+       \(aqmount_id\(aq に一致するマウントを探すことで行う。 */
+
+    if (argc > 1)
+        mount_fd = open(argv[1], O_RDONLY);
+    else
+        mount_fd = open_mount_path_by_id(mount_id);
+
+    if (mount_fd == \-1)
+        errExit("opening mount fd");
+
+    /* ハンドルとマウントポイントを使ってファイルをオープンする */
+
+    fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);
+    if (fd == \-1)
+        errExit("open_by_handle_at");
+
+    /* そのファイルからバイトを読み出す */
+
+    nread = read(fd, buf, sizeof(buf));
+    if (nread == \-1)
+        errExit("read");
+
+    printf("Read %zd bytes\en", nread);
+
+    exit(EXIT_SUCCESS);
+}
+.fi
+.SH 関連項目
+\fBopen\fP(2), \fBlibblkid\fP(3), \fBblkid\fP(8), \fBfindfs\fP(8), \fBmount\fP(8)
+
+.UR https://www.kernel.org/pub/linux/utils/util\-linux/
+.UE
+で入手できる最新の
+\fIutil\-linux\fP リリースの \fIlibblkid\fP と \fIlibmount\fP のドキュメント。
+.SH この文書について
+この man ページは Linux \fIman\-pages\fP プロジェクトのリリース 3.78 の一部
+である。プロジェクトの説明とバグ報告に関する情報は
+http://www.kernel.org/doc/man\-pages/ に書かれている。
index 238d286..e69de29 100644 (file)
@@ -1,2 +0,0 @@
-# pagename,#complete,#remaining,#all
-open_by_handle_at.2,128,16,144
index 294b053..a0a7a76 100644 (file)
 @:LDP man-pages:3.78:2014/04/14:munlock:2:mlock:2:
 @:LDP man-pages:3.78:2014/04/14:munlockall:2:mlock:2:
 @:LDP man-pages:3.78:2015/01/22:munmap:2:mmap:2:
-:LDP man-pages:3.78:2014/06/13:name_to_handle_at:2:open_by_handle_at:2:
+:LDP man-pages:3.78:2014/06/13:name_to_handle_at:2:open_by_handle_at:2:
 ○:LDP man-pages:3.78:2013/07/30:nanosleep:2:2015/01/24::amotoki@gmail.com:Akihiro Motoki:
 ○:LDP man-pages:3.78:2013/09/17:nfsservctl:2:2015/01/24::amotoki@gmail.com:Akihiro Motoki:
 ○:LDP man-pages:3.78:2014/04/28:nice:2:2015/01/24::amotoki@gmail.com:Akihiro Motoki:
 @:LDP man-pages:3.78:2014/08/19:oldstat:2:stat:2:
 @:LDP man-pages:3.78:2014/09/21:olduname:2:uname:2:
 ○:LDP man-pages:3.78:2015/01/22:open:2:2015/01/24::amotoki@gmail.com:Akihiro Motoki:
-×:LDP man-pages:3.78:2014/06/13:open_by_handle_at:2:::::
+○:LDP man-pages:3.78:2014/06/13:open_by_handle_at:2:2015/01/24::amotoki@gmail.com:Akihiro Motoki:
 @:LDP man-pages:3.78:2015/01/22:openat:2:open:2:
 ○:LDP man-pages:3.78:2012/12/31:outb:2:2015/01/24::argrath@ub32.org:Kentaro Shirakata:
 @:LDP man-pages:3.78:2012/12/31:outb_p:2:outb:2:
index 7b3344d..701f3dc 100644 (file)
 <TR><TD>cciss.4</TD><TD>44/88</TD><TD>50.00</TD></TR>
 <TR><TD>cpuid.4</TD><TD>13/24</TD><TD>45.83</TD></TR>
 <TR><TD>hpsa.4</TD><TD>23/57</TD><TD>59.65</TD></TR>
-<TR><TD ALIGN="center" COLSPAN=3 BGCOLOR="Yellow"><B>stdio</B></TD></TR>
-<TR class="over80"><TD>open_by_handle_at.2</TD><TD>16/144</TD><TD>88.89</TD></TR>
 <TR><TD ALIGN="center" COLSPAN=3 BGCOLOR="Yellow"><B>stdlib</B></TD></TR>
 <TR><TD>getauxval.3</TD><TD>34/86</TD><TD>60.47</TD></TR>
 <TR><TD>vdso.7</TD><TD>139/184</TD><TD>24.46</TD></TR>
-<TR><TD COLSPAN=3>Total 46 pages</TD></TR>
+<TR><TD COLSPAN=3>Total 45 pages</TD></TR>
 </TABLE>
 </BODY></HTML>