summaryrefslogtreecommitdiff
path: root/lib9p/idl
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-01-14 20:14:46 -0700
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-01-14 20:14:46 -0700
commit287e11381634b879dc82b23eacb693a31c52f9ef (patch)
tree236d11893dafb8f45141fdacc7d6f47cc0aa8529 /lib9p/idl
parentf7c75fe0113cdbd3e13b4e22edf76d9456c4b064 (diff)
parent6e48efec92b3357b2b762d14994d2f812a3b6ef7 (diff)
Merge branch 'lukeshu/9p-idl-defs'
Diffstat (limited to 'lib9p/idl')
-rw-r--r--lib9p/idl/0000-README.md23
-rw-r--r--lib9p/idl/1992-9P0.9p.wip71
-rw-r--r--lib9p/idl/1995-9P1.9p.wip71
-rw-r--r--lib9p/idl/2002-9P2000.9p17
-rw-r--r--lib9p/idl/2005-9P2000.u.9p16
-rw-r--r--lib9p/idl/2010-9P2000.L.9p.wip132
-rw-r--r--lib9p/idl/__init__.py31
7 files changed, 231 insertions, 130 deletions
diff --git a/lib9p/idl/0000-README.md b/lib9p/idl/0000-README.md
index 86862b7..036de22 100644
--- a/lib9p/idl/0000-README.md
+++ b/lib9p/idl/0000-README.md
@@ -1,7 +1,7 @@
<!--
lib9p/idl/0000-README.md - Overview of 9P protocol definitions
- Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
@@ -35,7 +35,7 @@ bitfields,
structures,
- struct STRUCTNAME = "FILENAME[FIELDTYPE]..."
+ struct STRUCTNAME = "FIELDNAME[FIELDTYPE]..."
and messages (which are a special-case of structures).
@@ -44,8 +44,21 @@ and messages (which are a special-case of structures).
Struct fields that have numeric types (either primitives or `num`
types) can add to their type `,val=` and/or `,max=` to specify what
the exact value must be and/or what the maximum (inclusive) value is.
+A field that is repeated a variable number of times be wrapped in
+parenthesis and prefixed with the fieldname containing that count:
+`OTHERFIELDNAME*(FIELDNAME[FIELDTYPE])`.
`,val=` and `,max` take a string of `+`/`-` tokens and values; a value
-can either be a decimal numeric constant (eg: `107`), the `&fieldname`
-to refer to the offset of a field name in that struct, or the special
-value `end` to refer to the offset of the end of the struct.
+can be
+ - a decimal numeric constant (eg: `107`),
+ - `&fieldname` to refer to the offset of a field name in that struct,
+ - the special value `end` to refer to the offset of the end of the
+ struct,
+ - the special value `s32_max` to refer to the constant value
+ `(1<<31)-1`, or
+ - the special value `s64_max` to refer to the constant value
+ `(1<<63)-1`
+
+A parser for this syntax is given in `__init__.py`. However,
+`__init__.py` places the somewhat arbitrary undocumented restrictions
+on fields referenced as the count for a repeated field.
diff --git a/lib9p/idl/1992-9P0.9p.wip b/lib9p/idl/1992-9P0.9p.wip
index 27d6b33..15997d9 100644
--- a/lib9p/idl/1992-9P0.9p.wip
+++ b/lib9p/idl/1992-9P0.9p.wip
@@ -1,6 +1,6 @@
# lib9p/idl/1992-9P0.9p - Definitions of 9P0 (Plan 9 1st ed) messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
# https://man.cat-v.org/plan_9_1st_ed/5/
@@ -18,36 +18,39 @@ struct qid = "path[4] version[4]"
# a nul-padded string
struct name = 28*(txt[1])
-msg Tnop = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Rnop = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Tsession = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Rsession = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Rerror = "typ[1,val=TODO] tag[tag] ename[64]"
-msg Tflush = "typ[1,val=TODO] tag[tag] oldtag[tag]"
-msg Rflush = "typ[1,val=TODO] tag[tag]"
-msg Tauth = "typ[1,val=TODO] tag[tag] fid[fid] uid[28] chal[36]"
-msg Rauth = "typ[1,val=TODO] tag[tag] fid[fid] chal[30]"
-msg Tattach = "typ[1,val=TODO] tag[tag] fid[fid] uid[28] aname[28] auth[28]"
-msg Rattach = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Tclone = "typ[1,val=TODO] tag[tag] fid[fid] newfid[fid]"
-msg Rclone = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tclwalk = "typ[1,val=TODO] tag[tag] fid[fid] newfid[fid] name[28]"
-msg Rclwalk = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Twalk = "typ[1,val=TODO] tag[tag] fid[fid] name[28]"
-msg Rwalk = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Topen = "typ[1,val=TODO] tag[tag] fid[fid] mode[1]"
-msg Ropen = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Tcreate = "typ[1,val=TODO] tag[tag] fid[fid] name[28] perm[4] mode[1]"
-msg Rcreate = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Tread = "typ[1,val=TODO] tag[tag] fid[fid] offset[8] count[2,max=8192]"
-msg Rread = "typ[1,val=TODO] tag[tag] fid[fid] count[2,max=8192] pad[1] count*(data[1])"
-msg Twrite = "typ[1,val=TODO] tag[tag] fid[fid] offset[8] count[2,max=8192] pad[1] count*(data[1])"
-msg Rwrite = "typ[1,val=TODO] tag[tag] fid[fid] count[2,max=8192]"
-msg Tclunk = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rclunk = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tremove = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rremove = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tstat = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rstat = "typ[1,val=TODO] tag[tag] fid[fid] stat[116]"
-msg Twstat = "typ[1,val=TODO] tag[tag] fid[fid] stat[116]"
-msg Rwstat = "typ[1,val=TODO] tag[tag] fid[fid]"
+msg Tmux = "typ[1,val=48] mux[2]" # Undocumented, but implemented by mux(3) / libmux.a
+#msg Rmux = "typ[1,val=49] illegal"
+msg Tnop = "typ[1,val=50] tag[tag,val=0xFFFF]"
+msg Rnop = "typ[1,val=51] tag[tag,val=0xFFFF]"
+msg Tsession = "typ[1,val=52] tag[tag,val=0xFFFF]"
+msg Rsession = "typ[1,val=53] tag[tag,val=0xFFFF]"
+#msg Terror = "typ[1,val=54] illegal"
+msg Rerror = "typ[1,val=55] tag[tag] ename[64]"
+msg Tflush = "typ[1,val=56] tag[tag] oldtag[tag]"
+msg Rflush = "typ[1,val=57] tag[tag]"
+msg Tattach = "typ[1,val=58] tag[tag] fid[fid] uid[28] aname[28] auth[28]"
+msg Rattach = "typ[1,val=59] tag[tag] fid[fid] qid[8]"
+msg Tclone = "typ[1,val=60] tag[tag] fid[fid] newfid[fid]"
+msg Rclone = "typ[1,val=61] tag[tag] fid[fid]"
+msg Twalk = "typ[1,val=62] tag[tag] fid[fid] name[28]"
+msg Rwalk = "typ[1,val=63] tag[tag] fid[fid] qid[8]"
+msg Topen = "typ[1,val=64] tag[tag] fid[fid] mode[1]"
+msg Ropen = "typ[1,val=65] tag[tag] fid[fid] qid[8]"
+msg Tcreate = "typ[1,val=66] tag[tag] fid[fid] name[28] perm[4] mode[1]"
+msg Rcreate = "typ[1,val=67] tag[tag] fid[fid] qid[8]"
+msg Tread = "typ[1,val=68] tag[tag] fid[fid] offset[8] count[2,max=8192]"
+msg Rread = "typ[1,val=69] tag[tag] fid[fid] count[2,max=8192] pad[1] count*(data[1])"
+msg Twrite = "typ[1,val=70] tag[tag] fid[fid] offset[8] count[2,max=8192] pad[1] count*(data[1])"
+msg Rwrite = "typ[1,val=71] tag[tag] fid[fid] count[2,max=8192]"
+msg Tclunk = "typ[1,val=72] tag[tag] fid[fid]"
+msg Rclunk = "typ[1,val=73] tag[tag] fid[fid]"
+msg Tremove = "typ[1,val=74] tag[tag] fid[fid]"
+msg Rremove = "typ[1,val=75] tag[tag] fid[fid]"
+msg Tstat = "typ[1,val=76] tag[tag] fid[fid]"
+msg Rstat = "typ[1,val=77] tag[tag] fid[fid] stat[116]"
+msg Twstat = "typ[1,val=78] tag[tag] fid[fid] stat[116]"
+msg Rwstat = "typ[1,val=79] tag[tag] fid[fid]"
+msg Tclwalk = "typ[1,val=80] tag[tag] fid[fid] newfid[fid] name[28]"
+msg Rclwalk = "typ[1,val=81] tag[tag] fid[fid] qid[8]"
+msg Tauth = "typ[1,val=82] tag[tag] fid[fid] uid[28] chal[36]"
+msg Rauth = "typ[1,val=83] tag[tag] fid[fid] chal[30]"
diff --git a/lib9p/idl/1995-9P1.9p.wip b/lib9p/idl/1995-9P1.9p.wip
index 30b9112..2812cda 100644
--- a/lib9p/idl/1995-9P1.9p.wip
+++ b/lib9p/idl/1995-9P1.9p.wip
@@ -1,6 +1,6 @@
# lib9p/idl/1995-9P1.9p - Definitions of 9P1 (Plan 9 2nd ed and 3rd ed) messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
# https://man.cat-v.org/plan_9_2nd_ed/5/
@@ -19,34 +19,41 @@ struct qid = "path[4] version[4]"
# a nul-padded string
struct name = 28*(txt[1])
-msg Tnop = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Rnop = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Tsession = "typ[1,val=TODO] tag[tag,val=0xFFFF] chal[8]"
-msg Rsession = "typ[1,val=TODO] tag[tag,val=0xFFFF] chal[8] authid[28] authdom[48]"
-msg Rerror = "typ[1,val=TODO] tag[tag] ename[64]"
-msg Tflush = "typ[1,val=TODO] tag[tag] oldtag[tag]"
-msg Rflush = "typ[1,val=TODO] tag[tag]"
-msg Tattach = "typ[1,val=TODO] tag[tag] fid[fid] uid[28] aname[28] ticket[72] auth[13]"
-msg Rattach = "typ[1,val=TODO] tag[tag] fid[fid] qid[8] rauth[13]"
-msg Tclone = "typ[1,val=TODO] tag[tag] fid[fid] newfid[fid]"
-msg Rclone = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tclwalk = "typ[1,val=TODO] tag[tag] fid[fid] newfid[fid] name[28]"
-msg Rclwalk = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Twalk = "typ[1,val=TODO] tag[tag] fid[fid] name[28]"
-msg Rwalk = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Topen = "typ[1,val=TODO] tag[tag] fid[fid] mode[1]"
-msg Ropen = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Tcreate = "typ[1,val=TODO] tag[tag] fid[fid] name[28] perm[4] mode[1]"
-msg Rcreate = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Tread = "typ[1,val=TODO] tag[tag] fid[fid] offset[8] count[2,max=8192]"
-msg Rread = "typ[1,val=TODO] tag[tag] fid[fid] count[2,max=8192] pad[1] count*(data[1])"
-msg Twrite = "typ[1,val=TODO] tag[tag] fid[fid] offset[8] count[2,max=8192] pad[1] count*(data[1])"
-msg Rwrite = "typ[1,val=TODO] tag[tag] fid[fid] count[2,max=8192]"
-msg Tclunk = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rclunk = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tremove = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rremove = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tstat = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rstat = "typ[1,val=TODO] tag[tag] fid[fid] stat[116]"
-msg Twstat = "typ[1,val=TODO] tag[tag] fid[fid] stat[116]"
-msg Rwstat = "typ[1,val=TODO] tag[tag] fid[fid]"
+msg Tnop = "typ[1,val=50] tag[tag,val=0xFFFF]"
+msg Rnop = "typ[1,val=51] tag[tag,val=0xFFFF]"
+#msg Tosession = "typ[1,val=52] illegal"
+#msg Rosession = "typ[1,val=53] illegal"
+#msg Terror = "typ[1,val=54] illegal"
+msg Rerror = "typ[1,val=55] tag[tag] ename[64]"
+msg Tflush = "typ[1,val=56] tag[tag] oldtag[tag]"
+msg Rflush = "typ[1,val=57] tag[tag]"
+#msg Toattach = "typ[1,val=58] illegal"
+#msg Roattach = "typ[1,val=59] illegal"
+msg Tclone = "typ[1,val=60] tag[tag] fid[fid] newfid[fid]"
+msg Rclone = "typ[1,val=61] tag[tag] fid[fid]"
+msg Twalk = "typ[1,val=62] tag[tag] fid[fid] name[28]"
+msg Rwalk = "typ[1,val=63] tag[tag] fid[fid] qid[8]"
+msg Topen = "typ[1,val=64] tag[tag] fid[fid] mode[1]"
+msg Ropen = "typ[1,val=65] tag[tag] fid[fid] qid[8]"
+msg Tcreate = "typ[1,val=66] tag[tag] fid[fid] name[28] perm[4] mode[1]"
+msg Rcreate = "typ[1,val=67] tag[tag] fid[fid] qid[8]"
+msg Tread = "typ[1,val=68] tag[tag] fid[fid] offset[8,max=s64_max] count[2,max=8192]"
+msg Rread = "typ[1,val=69] tag[tag] fid[fid] count[2,max=8192] pad[1] count*(data[1])"
+msg Twrite = "typ[1,val=70] tag[tag] fid[fid] offset[8] count[2,max=8192] pad[1] count*(data[1])"
+msg Rwrite = "typ[1,val=71] tag[tag] fid[fid] count[2,max=8192]"
+msg Tclunk = "typ[1,val=72] tag[tag] fid[fid]"
+msg Rclunk = "typ[1,val=73] tag[tag] fid[fid]"
+msg Tremove = "typ[1,val=74] tag[tag] fid[fid]"
+msg Rremove = "typ[1,val=75] tag[tag] fid[fid]"
+msg Tstat = "typ[1,val=76] tag[tag] fid[fid]"
+msg Rstat = "typ[1,val=77] tag[tag] fid[fid] stat[116]"
+msg Twstat = "typ[1,val=78] tag[tag] fid[fid] stat[116]"
+msg Rwstat = "typ[1,val=79] tag[tag] fid[fid]"
+msg Tclwalk = "typ[1,val=80] tag[tag] fid[fid] newfid[fid] name[28]"
+msg Rclwalk = "typ[1,val=81] tag[tag] fid[fid] qid[8]"
+#msg Toauth = typ[1,val=82] illegal"
+#msg Roauth = typ[1,val=83] illegal"
+msg Tsession = "typ[1,val=84] tag[tag,val=0xFFFF] chal[8]"
+msg Rsession = "typ[1,val=85] tag[tag,val=0xFFFF] chal[8] authid[28] authdom[48]"
+msg Tattach = "typ[1,val=86] tag[tag] fid[fid] uid[28] aname[28] ticket[72] auth[13]"
+msg Rattach = "typ[1,val=87] tag[tag] fid[fid] qid[8] rauth[13]"
diff --git a/lib9p/idl/2002-9P2000.9p b/lib9p/idl/2002-9P2000.9p
index c83f439..c1cd74b 100644
--- a/lib9p/idl/2002-9P2000.9p
+++ b/lib9p/idl/2002-9P2000.9p
@@ -1,6 +1,6 @@
# lib9p/idl/2002-9P2000.9p - Definitions of 9P2000 messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
# "9P2000" base protocol
@@ -9,21 +9,26 @@
#
# But due to incompleteness of the draft RFC, the Plan 9 manual
# section-5 and the Plan 9 headers (particularly fcall.h) are often
-# better references.
+# better references. The s{32,64}_max limitations are not documented
+# in the draft RFC or the manual pages, but have been enforced by
+# lib9p/srv.c in every release of Plan 9 4e.
#
# https://github.com/plan9foundation/plan9/tree/main/sys/man/5
# https://man.cat-v.org/plan_9/5/
# https://github.com/plan9foundation/plan9/blob/main/sys/include/fcall.h
+# https://github.com/plan9foundation/plan9/blob/main/sys/src/lib9p/srv.c
version "9P2000"
# tag - identify a request/response pair
num tag = 2
+ "NOTAG = ~0"
# file identifier - like a UNIX file-descriptor
num fid = 4
+ "NOFID = ~0"
-# data - u32le `n`, then `n` bytes of data
-struct d = "len[4] len*(dat[1])"
+# data - s32le `n`, then `n` bytes of data
+struct d = "len[4,max=s32_max] len*(dat[1])"
# string - u16le `n`, then `n` bytes of UTF-8, without any nul-bytes
struct s = "len[2] len*(utf8[1])"
@@ -136,9 +141,9 @@ msg Topen = "size[4,val=end-&size] typ[1,val=112] tag[tag] fid[fid] mode[o]"
msg Ropen = "size[4,val=end-&size] typ[1,val=113] tag[tag] qid[qid] iounit[4]"
msg Tcreate = "size[4,val=end-&size] typ[1,val=114] tag[tag] fid[fid] name[s] perm[dm] mode[o]"
msg Rcreate = "size[4,val=end-&size] typ[1,val=115] tag[tag] qid[qid] iounit[4]"
-msg Tread = "size[4,val=end-&size] typ[1,val=116] tag[tag] fid[fid] offset[8] count[4]"
+msg Tread = "size[4,val=end-&size] typ[1,val=116] tag[tag] fid[fid] offset[8,max=s64_max] count[4,max=s32_max]"
msg Rread = "size[4,val=end-&size] typ[1,val=117] tag[tag] data[d]" # for directories `data` is the sequence "cnt*(entries[stat])"
-msg Twrite = "size[4,val=end-&size] typ[1,val=118] tag[tag] fid[fid] offset[8] data[d]"
+msg Twrite = "size[4,val=end-&size] typ[1,val=118] tag[tag] fid[fid] offset[8,max=s64_max] data[d]"
msg Rwrite = "size[4,val=end-&size] typ[1,val=119] tag[tag] count[4]"
msg Tclunk = "size[4,val=end-&size] typ[1,val=120] tag[tag] fid[fid]"
msg Rclunk = "size[4,val=end-&size] typ[1,val=121] tag[tag]"
diff --git a/lib9p/idl/2005-9P2000.u.9p b/lib9p/idl/2005-9P2000.u.9p
index 3eab4ad..d96bbce 100644
--- a/lib9p/idl/2005-9P2000.u.9p
+++ b/lib9p/idl/2005-9P2000.u.9p
@@ -1,6 +1,6 @@
# lib9p/idl/2005-9P2000.u.9p - Definitions of 9P2000.u messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
# "9P2000.u" Unix extension
@@ -10,13 +10,17 @@ version "9P2000.u"
from ./2002-9P2000.9p import *
+# numeric user ID
+num nuid = 4
+ "NONUID = ~0"
+
struct stat += "file_extension[s]"
- "file_owner_n_uid[4]"
- "file_owner_n_gid[4]"
- "file_last_modified_n_uid[4]"
+ "file_owner_n_uid[nuid]"
+ "file_owner_n_gid[nuid]"
+ "file_last_modified_n_uid[nuid]"
-msg Tauth += "n_uname[4]"
-msg Tattach += "n_uname[4]"
+msg Tauth += "n_uid[nuid]"
+msg Tattach += "n_uid[nuid]"
msg Rerror += "errno[4]"
diff --git a/lib9p/idl/2010-9P2000.L.9p.wip b/lib9p/idl/2010-9P2000.L.9p.wip
index f5e79c5..972e7d0 100644
--- a/lib9p/idl/2010-9P2000.L.9p.wip
+++ b/lib9p/idl/2010-9P2000.L.9p.wip
@@ -1,56 +1,106 @@
# lib9p/idl/2010-9P2000.L.9p - Definitions of 9P2000.L messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
# "9P2000.L" Linux extension
# https://github.com/chaos/diod/blob/master/protocol.md
version "9P2000.L"
-from ./2002-9P2000.9p import *
-from ./2005-9P2000.u.9p import Tauth, Tattach
+from ./2002-9P2000.9p import tag, fid, s, qt, qid, Tversion, Rversion, Tflush, Rflush, Twalk, Rwalk, Tread, Rread, Twrite, Rwrite, Tclunk, RClunk, Tremove, Rremove
+from ./2005-9P2000.u.9p import nuid, Tauth, Rauth, Tattach, Rattach
+
+bitfield getattr = 8
+ "0=MODE"
+ "1=NLINK"
+ "2=UID"
+ "3=GID"
+ "4=RDEV"
+ "5=ATIME"
+ "6=MTIME"
+ "7=CTIME"
+ "8=INO"
+ "9=SIZE"
+ "10=BLOCKS"
+
+ "11=BTIME"
+ "12=GEN"
+ "13=DATA_VERSION"
+
+ "BASIC=0x000007ff" # Mask for fields up to BLOCKS
+ "ALL =0x00003fff" # Mask for All fields above
+
+bitfield setattr = 4
+ "0=MODE"
+ "1=UID"
+ "2=GID"
+ "3=SIZE"
+ "4=ATIME"
+ "5=MTIME"
+ "6=CTIME"
+ "7=ATIME_SET"
+ "8=MTIME_SET"
+
+num lock_type = 1
+ "RDLCK=0"
+ "WRLCK=1"
+ "UNLCK=2"
+
+bitfield lock_flags = 4
+ "0=BLOCK"
+ "1=RECLAIM"
+
+num lock_status = 1
+ "SUCCESS=0"
+ "BLOCKED=1"
+ "ERROR=2"
+ "GRACE=3"
#msg Tlerror = "size[4,val=end-&size] typ[1,val=6] tag[tag] illegal" # analogous to 106/Terror
msg Rlerror = "size[4,val=end-&size] typ[1,val=7] tag[tag] ecode[4]" # analogous to 107/Rerror
-msg Tstatfs = "size[4,val=end-&size] typ[1,val=8] tag[tag] TODO"
-msg Rstatfs = "size[4,val=end-&size] typ[1,val=9] tag[tag] TODO"
-msg Tlopen = "size[4,val=end-&size] typ[1,val=12] tag[tag] TODO" # analogous to 112/Topen
-msg Rlopen = "size[4,val=end-&size] typ[1,val=13] tag[tag] TODO" # analogous to 113/Ropen
-msg Tlcreate = "size[4,val=end-&size] typ[1,val=14] tag[tag] TODO" # analogous to 114/Tcreate
-msg Rlcreate = "size[4,val=end-&size] typ[1,val=15] tag[tag] TODO" # analogous to 115/Rcreate
-msg Tsymlink = "size[4,val=end-&size] typ[1,val=16] tag[tag] TODO"
-msg Rsymlink = "size[4,val=end-&size] typ[1,val=17] tag[tag] TODO"
-msg Tmknod = "size[4,val=end-&size] typ[1,val=18] tag[tag] TODO"
-msg Rmknod = "size[4,val=end-&size] typ[1,val=19] tag[tag] TODO"
-msg Trename = "size[4,val=end-&size] typ[1,val=20] tag[tag] TODO"
-msg Rrename = "size[4,val=end-&size] typ[1,val=21] tag[tag] TODO"
-msg Treadlink = "size[4,val=end-&size] typ[1,val=22] tag[tag] TODO"
-msg Rreadlink = "size[4,val=end-&size] typ[1,val=23] tag[tag] TODO"
-msg Tgetattr = "size[4,val=end-&size] typ[1,val=24] tag[tag] TODO"
-msg Rgetattr = "size[4,val=end-&size] typ[1,val=25] tag[tag] TODO"
-msg Tsetattr = "size[4,val=end-&size] typ[1,val=26] tag[tag] TODO"
-msg Rsetattr = "size[4,val=end-&size] typ[1,val=27] tag[tag] TODO"
+msg Tstatfs = "size[4,val=end-&size] typ[1,val=8] tag[tag] fid[fid]"
+msg Rstatfs = "size[4,val=end-&size] typ[1,val=9] tag[tag] type[4] bsize[4] blocks[8] bfree[8] bavail[8] files[8] ffree[8] fsid[8] namelen[4]"
+msg Tlopen = "size[4,val=end-&size] typ[1,val=12] tag[tag] fid[fid] flags[4]" # analogous to 112/Topen
+msg Rlopen = "size[4,val=end-&size] typ[1,val=13] tag[tag] qid[qid] iounit[4]" # analogous to 113/Ropen
+msg Tlcreate = "size[4,val=end-&size] typ[1,val=14] tag[tag] fid[fid] name[s] flags[4] mode[4] gid[nuid]" # analogous to 114/Tcreate
+msg Rlcreate = "size[4,val=end-&size] typ[1,val=15] tag[tag] qid[qid] iounit[4]" # analogous to 115/Rcreate
+msg Tsymlink = "size[4,val=end-&size] typ[1,val=16] tag[tag] fid[fid] name[s] symtgt[s] gid[nuid]"
+msg Rsymlink = "size[4,val=end-&size] typ[1,val=17] tag[tag] qid[qid]"
+msg Tmknod = "size[4,val=end-&size] typ[1,val=18] tag[tag] dfid[fid] name[s] mode[4] major[4] minor[4] gid[nuid]"
+msg Rmknod = "size[4,val=end-&size] typ[1,val=19] tag[tag] qid[qid]"
+msg Trename = "size[4,val=end-&size] typ[1,val=20] tag[tag] fid[fid] dfid[fid] name[s]"
+msg Rrename = "size[4,val=end-&size] typ[1,val=21] tag[tag]"
+msg Treadlink = "size[4,val=end-&size] typ[1,val=22] tag[tag] fid[fid]"
+msg Rreadlink = "size[4,val=end-&size] typ[1,val=23] tag[tag] target[s]"
+msg Tgetattr = "size[4,val=end-&size] typ[1,val=24] tag[tag] fid[fid] request_mask[getattr]"
+msg Rgetattr = "size[4,val=end-&size] typ[1,val=25] tag[tag] valid[8] qid[qid] mode[4] uid[nuid] gid[nuid] nlink[8]"
+ "rdev[8] filesize[8] blksize[8] blocks[8]"
+ "atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]"
+ "ctime_sec[8] ctime_nsec[8] btime_sec[8] btime_nsec[8]"
+ "gen[8] data_version[8]"
+msg Tsetattr = "size[4,val=end-&size] typ[1,val=26] tag[tag] fid[fid] valid[setattr] mode[4] uid[nuid] gid[nuid] filesize[8] atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]"
+msg Rsetattr = "size[4,val=end-&size] typ[1,val=27] tag[tag]"
#...
-msg Txattrwalk = "size[4,val=end-&size] typ[1,val=30] tag[tag] TODO"
-msg Rxattrwalk = "size[4,val=end-&size] typ[1,val=31] tag[tag] TODO"
-msg Txattrcreate = "size[4,val=end-&size] typ[1,val=32] tag[tag] TODO"
-msg Rxattrcreate = "size[4,val=end-&size] typ[1,val=33] tag[tag] TODO"
+msg Txattrwalk = "size[4,val=end-&size] typ[1,val=30] tag[tag] fid[fid] newfid[fid] name[s]"
+msg Rxattrwalk = "size[4,val=end-&size] typ[1,val=31] tag[tag] attr_size[8]"
+msg Txattrcreate = "size[4,val=end-&size] typ[1,val=32] tag[tag] fid[fid] name[s] attr_size[8] flags[4]"
+msg Rxattrcreate = "size[4,val=end-&size] typ[1,val=33] tag[tag]"
#...
-msg Treaddir = "size[4,val=end-&size] typ[1,val=40] tag[tag] TODO"
-msg Rreaddir = "size[4,val=end-&size] typ[1,val=41] tag[tag] TODO"
+msg Treaddir = "size[4,val=end-&size] typ[1,val=40] tag[tag] fid[fid] offset[8] count[4]"
+msg Rreaddir = "size[4,val=end-&size] typ[1,val=41] tag[tag] count[4] count*(data[1])" # data is "qid[qid] offset[8] type[1] name[s]"
#...
-msg Tfsync = "size[4,val=end-&size] typ[1,val=50] tag[tag] TODO"
-msg Rfsync = "size[4,val=end-&size] typ[1,val=51] tag[tag] TODO"
-msg Tlock = "size[4,val=end-&size] typ[1,val=52] tag[tag] TODO"
-msg Rlock = "size[4,val=end-&size] typ[1,val=53] tag[tag] TODO"
-msg Tgetlock = "size[4,val=end-&size] typ[1,val=54] tag[tag] TODO"
-msg Rgetlock = "size[4,val=end-&size] typ[1,val=55] tag[tag] TODO"
+msg Tfsync = "size[4,val=end-&size] typ[1,val=50] tag[tag] fid[fid] datasync[4]"
+msg Rfsync = "size[4,val=end-&size] typ[1,val=51] tag[tag]"
+msg Tlock = "size[4,val=end-&size] typ[1,val=52] tag[tag] fid[fid] type[lock_type] flags[lock_flags] start[8] length[8] proc_id[4] client_id[s]"
+msg Rlock = "size[4,val=end-&size] typ[1,val=53] tag[tag] status[lock_status]"
+msg Tgetlock = "size[4,val=end-&size] typ[1,val=54] tag[tag] fid[fid] type[1] start[8] length[8] proc_id[4] client_id[s]"
+msg Rgetlock = "size[4,val=end-&size] typ[1,val=55] tag[tag] type[1] start[8] length[8] proc_id[4] client_id[s]"
# ...
-msg Tlink = "size[4,val=end-&size] typ[1,val=70] tag[tag] TODO"
-msg Rlink = "size[4,val=end-&size] typ[1,val=71] tag[tag] TODO"
-msg Tmkdir = "size[4,val=end-&size] typ[1,val=72] tag[tag] TODO"
-msg Tmkdir = "size[4,val=end-&size] typ[1,val=73] tag[tag] TODO"
-msg Trenameat = "size[4,val=end-&size] typ[1,val=74] tag[tag] TODO"
-msg Rrenameat = "size[4,val=end-&size] typ[1,val=75] tag[tag] TODO"
-msg Tunlinkat = "size[4,val=end-&size] typ[1,val=76] tag[tag] TODO"
-msg Runlinkat = "size[4,val=end-&size] typ[1,val=77] tag[tag] TODO"
+msg Tlink = "size[4,val=end-&size] typ[1,val=70] tag[tag] dfid[fid] fid[fid] name[s]"
+msg Rlink = "size[4,val=end-&size] typ[1,val=71] tag[tag]"
+msg Tmkdir = "size[4,val=end-&size] typ[1,val=72] tag[tag] dfid[fid] name[s] mode[4] gid[nuid]"
+msg Tmkdir = "size[4,val=end-&size] typ[1,val=73] tag[tag] qid[qid]"
+msg Trenameat = "size[4,val=end-&size] typ[1,val=74] tag[tag] olddirfid[fid] oldname[s] newdirfid[fid] newname[s]"
+msg Rrenameat = "size[4,val=end-&size] typ[1,val=75] tag[tag]"
+msg Tunlinkat = "size[4,val=end-&size] typ[1,val=76] tag[tag] dirfd[fid] name[s] flags[4]"
+msg Runlinkat = "size[4,val=end-&size] typ[1,val=77] tag[tag]"
diff --git a/lib9p/idl/__init__.py b/lib9p/idl/__init__.py
index 920d02d..ab45ed0 100644
--- a/lib9p/idl/__init__.py
+++ b/lib9p/idl/__init__.py
@@ -1,12 +1,12 @@
# lib9p/idl/__init__.py - A parser for .9p specification files.
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
import enum
import os.path
import re
-from typing import Callable, Literal, TypeAlias, TypeVar, cast
+from typing import Callable, Literal, TypeVar, cast
__all__ = [
# entrypoint
@@ -50,8 +50,11 @@ class Number:
prim: Primitive
+ vals: dict[str, str]
+
def __init__(self) -> None:
self.in_versions = set()
+ self.vals = {}
@property
def static_size(self) -> int:
@@ -181,8 +184,7 @@ class Message(Struct):
return self.members[1].val.tokens[0].val
-Type: TypeAlias = Primitive | Number | Bitfield | Struct | Message
-# type Type = Primitive | Number | Bitfield | Struct | Message # Change to this once we have Python 3.13
+type Type = Primitive | Number | Bitfield | Struct | Message
T = TypeVar("T", Number, Bitfield, Struct, Message)
# Parse ########################################################################
@@ -196,12 +198,27 @@ re_memtype = f"(?:{re_symname}|{re_priname})" # typenames that a struct member
re_expr = f"(?:(?:-|\\+|[0-9]+|&?{re_symname})+)"
+re_numspec = f"(?P<name>{re_symname})\\s*=\\s*(?P<val>\\S+)"
+
re_bitspec_bit = f"(?P<bit>[0-9]+)\\s*=\\s*(?P<name>{re_symname})"
re_bitspec_alias = f"(?P<name>{re_symname})\\s*=\\s*(?P<val>\\S+)"
re_memberspec = f"(?:(?P<cnt>{re_symname})\\*\\()?(?P<name>{re_symname})\\[(?P<typ>{re_memtype})(?:,max=(?P<max>{re_expr})|,val=(?P<val>{re_expr}))*\\]\\)?"
+def parse_numspec(ver: str, n: Number, spec: str) -> None:
+ spec = spec.strip()
+
+ if m := re.fullmatch(re_numspec, spec):
+ name = m.group("name")
+ val = m.group("val")
+ if name in n.vals:
+ raise ValueError(f"{n.name}: name {repr(name)} already assigned")
+ n.vals[name] = val
+ else:
+ raise SyntaxError(f"invalid num spec {repr(spec)}")
+
+
def parse_bitspec(ver: str, bf: Bitfield, spec: str) -> None:
spec = spec.strip()
@@ -266,7 +283,7 @@ def parse_members(ver: str, env: dict[str, Type], struct: Struct, specs: str) ->
raise ValueError(f"duplicate member name {repr(member.name)}")
if m.group("typ") not in env:
- raise NameError(f"Unknown type {repr(m.group(2))}")
+ raise NameError(f"Unknown type {repr(m.group('typ'))}")
member.typ = env[m.group("typ")]
if cnt := m.group("cnt"):
@@ -434,6 +451,8 @@ def parse_file(
match prev:
case Bitfield():
parse_bitspec(version, prev, m.group("specs"))
+ case Number():
+ parse_numspec(version, prev, m.group("specs"))
case Struct(): # and Message()
parse_members(version, env, prev, m.group("specs"))
case _:
@@ -448,7 +467,7 @@ def parse_file(
typs: list[Type] = [x for x in env.values() if not isinstance(x, Primitive)]
for typ in [typ for typ in typs if isinstance(typ, Struct)]:
- valid_syms = ["end", *["&" + m.name for m in typ.members]]
+ valid_syms = ["end", "s32_max", "s64_max", *["&" + m.name for m in typ.members]]
for member in typ.members:
for tok in [*member.max.tokens, *member.val.tokens]:
if isinstance(tok, ExprSym) and tok.name not in valid_syms: