Update vendoring (#1304)
Update to current vendoring. Signed-off-by: Ben Kochie <superq@gmail.com>pull/1207/head
parent
b1298677aa
commit
e71e9f5a2f
14
go.mod
14
go.mod
|
@ -2,12 +2,14 @@ module github.com/prometheus/node_exporter
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/beevik/ntp v0.2.0
|
github.com/beevik/ntp v0.2.0
|
||||||
github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
|
||||||
github.com/ema/qdisc v0.0.0-20180104102928-b307c22d3ce7
|
github.com/ema/qdisc v0.0.0-20180104102928-b307c22d3ce7
|
||||||
github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968
|
github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968
|
||||||
|
github.com/golang/protobuf v1.3.1 // indirect
|
||||||
github.com/google/go-cmp v0.2.0 // indirect
|
github.com/google/go-cmp v0.2.0 // indirect
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||||
github.com/lufia/iostat v0.0.0-20170605150913-9f7362b77ad3
|
github.com/lufia/iostat v0.0.0-20170605150913-9f7362b77ad3
|
||||||
github.com/mattn/go-xmlrpc v0.0.0-20180914005235-ceecee2c45b7
|
github.com/mattn/go-xmlrpc v0.0.1
|
||||||
github.com/mdlayher/genetlink v0.0.0-20181016160152-e97704c1b795 // indirect
|
github.com/mdlayher/genetlink v0.0.0-20181016160152-e97704c1b795 // indirect
|
||||||
github.com/mdlayher/netlink v0.0.0-20181210160939-e069752bc835 // indirect
|
github.com/mdlayher/netlink v0.0.0-20181210160939-e069752bc835 // indirect
|
||||||
github.com/mdlayher/wifi v0.0.0-20180727163819-efdf3f4195d9
|
github.com/mdlayher/wifi v0.0.0-20180727163819-efdf3f4195d9
|
||||||
|
@ -16,11 +18,11 @@ require (
|
||||||
github.com/prometheus/common v0.2.0
|
github.com/prometheus/common v0.2.0
|
||||||
github.com/prometheus/procfs v0.0.0-20190209105433-f8d8b3f739bd
|
github.com/prometheus/procfs v0.0.0-20190209105433-f8d8b3f739bd
|
||||||
github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745
|
github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745
|
||||||
github.com/sirupsen/logrus v1.3.0 // indirect
|
github.com/sirupsen/logrus v1.4.1 // indirect
|
||||||
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a
|
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a
|
||||||
github.com/stretchr/testify v1.3.0 // indirect
|
github.com/stretchr/testify v1.3.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20190208162236-193df9c0f06f // indirect
|
golang.org/x/net v0.0.0-20190328230028-74de082e2cca // indirect
|
||||||
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 // indirect
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 // indirect
|
||||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503
|
golang.org/x/sys v0.0.0-20190402142545-baf5eb976a8c
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||||
)
|
)
|
||||||
|
|
31
go.sum
31
go.sum
|
@ -6,8 +6,8 @@ github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
|
||||||
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142 h1:3jFq2xL4ZajGK4aZY8jz+DAF0FHjI51BXjjSwCzS1Dk=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
|
||||||
github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -22,16 +22,20 @@ github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/lufia/iostat v0.0.0-20170605150913-9f7362b77ad3 h1:XGhvld9vIpj929Gri5ybjukYZeyZwKkFkqgATqBQiOs=
|
github.com/lufia/iostat v0.0.0-20170605150913-9f7362b77ad3 h1:XGhvld9vIpj929Gri5ybjukYZeyZwKkFkqgATqBQiOs=
|
||||||
github.com/lufia/iostat v0.0.0-20170605150913-9f7362b77ad3/go.mod h1:lRgtFVamD7L7GaXOSwBiuXMwU3Aicfn5h66LVs4u2SA=
|
github.com/lufia/iostat v0.0.0-20170605150913-9f7362b77ad3/go.mod h1:lRgtFVamD7L7GaXOSwBiuXMwU3Aicfn5h66LVs4u2SA=
|
||||||
github.com/mattn/go-xmlrpc v0.0.0-20180914005235-ceecee2c45b7 h1:BFoDwzrzyagR6/NO4av33U5jZCA5e0+PGzVrctY5Vu0=
|
github.com/mattn/go-xmlrpc v0.0.1 h1:JY8G+sH4jcjzZvxAY5P+wNrWA2WYC+aK+2bsYOl4z0Q=
|
||||||
github.com/mattn/go-xmlrpc v0.0.0-20180914005235-ceecee2c45b7/go.mod h1:jPxKbOGukjFCw9jFB7RRh3ZRQUehV22ryHP8IpREEx4=
|
github.com/mattn/go-xmlrpc v0.0.1/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mdlayher/genetlink v0.0.0-20181016160152-e97704c1b795 h1:2uvgdCvQ/MUubxqVhOFkeTaI0EZLcjPLVIwgZGWPgxs=
|
github.com/mdlayher/genetlink v0.0.0-20181016160152-e97704c1b795 h1:2uvgdCvQ/MUubxqVhOFkeTaI0EZLcjPLVIwgZGWPgxs=
|
||||||
|
@ -62,8 +66,8 @@ github.com/prometheus/procfs v0.0.0-20190209105433-f8d8b3f739bd/go.mod h1:TjEm7z
|
||||||
github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745 h1:IuH7WumZNax0D+rEqmy2TyhKCzrtMGqbZO0b8rO00JA=
|
github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745 h1:IuH7WumZNax0D+rEqmy2TyhKCzrtMGqbZO0b8rO00JA=
|
||||||
github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8=
|
github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
|
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
|
||||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a h1:os5OBNhwOwybXZMNLqT96XqtjdTtwRFw2w08uluvNeI=
|
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a h1:os5OBNhwOwybXZMNLqT96XqtjdTtwRFw2w08uluvNeI=
|
||||||
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a/go.mod h1:LeFCbQYJ3KJlPs/FvPz2dy1tkpxyeNESVyCNNzRXFR0=
|
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a/go.mod h1:LeFCbQYJ3KJlPs/FvPz2dy1tkpxyeNESVyCNNzRXFR0=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
@ -73,20 +77,23 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190208162236-193df9c0f06f h1:ETU2VEl7TnT5bl7IvuKEzTDpplg5wzGYsOCAPhdoEIg=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190208162236-193df9c0f06f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 h1:bfLnR+k0tq5Lqt6dflRLcZiz6UaXCMt3vhYJ1l4FQ80=
|
golang.org/x/net v0.0.0-20190328230028-74de082e2cca h1:hyA6yiAgbUwuWqtscNvWAI7U1CtlaD1KilQ6iudt1aI=
|
||||||
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503 h1:5SvYFrOM3W8Mexn9/oA44Ji7vhXAZQ9hiP+1Q/DMrWg=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190402142545-baf5eb976a8c h1:3xiKTkef8QqBJ8q+4fVUDMRoxnI0H/MVNFswa+aExbo=
|
||||||
|
golang.org/x/sys v0.0.0-20190402142545-baf5eb976a8c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|
|
@ -117,13 +117,13 @@ func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int,
|
||||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReloadOrRestart attempts a reload if the unit supports it and use a restart
|
// ReloadOrRestartUnit attempts a reload if the unit supports it and use a restart
|
||||||
// otherwise.
|
// otherwise.
|
||||||
func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try"
|
// ReloadOrTryRestartUnit attempts a reload if the unit supports it and use a "Try"
|
||||||
// flavored restart otherwise.
|
// flavored restart otherwise.
|
||||||
func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
|
||||||
|
@ -192,7 +192,7 @@ func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) {
|
||||||
return c.getProperties(path, "org.freedesktop.systemd1.Unit")
|
return c.getProperties(path, "org.freedesktop.systemd1.Unit")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUnitProperties takes the (escaped) unit path and returns all of its dbus object properties.
|
// GetUnitPathProperties takes the (escaped) unit path and returns all of its dbus object properties.
|
||||||
func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) {
|
func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) {
|
||||||
return c.getProperties(path, "org.freedesktop.systemd1.Unit")
|
return c.getProperties(path, "org.freedesktop.systemd1.Unit")
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ func (c *Conn) dispatch() {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns two unbuffered channels which will receive all changed units every
|
// SubscribeUnits returns two unbuffered channels which will receive all changed units every
|
||||||
// interval. Deleted units are sent as nil.
|
// interval. Deleted units are sent as nil.
|
||||||
func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) {
|
func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) {
|
||||||
return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil)
|
return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil)
|
||||||
|
|
|
@ -186,7 +186,6 @@ func (p *Buffer) DecodeVarint() (x uint64, err error) {
|
||||||
if b&0x80 == 0 {
|
if b&0x80 == 0 {
|
||||||
goto done
|
goto done
|
||||||
}
|
}
|
||||||
// x -= 0x80 << 63 // Always zero.
|
|
||||||
|
|
||||||
return 0, errOverflow
|
return 0, errOverflow
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
// Deprecated: do not use.
|
||||||
|
type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 }
|
||||||
|
|
||||||
|
// Deprecated: do not use.
|
||||||
|
func GetStats() Stats { return Stats{} }
|
||||||
|
|
||||||
|
// Deprecated: do not use.
|
||||||
|
func MarshalMessageSet(interface{}) ([]byte, error) {
|
||||||
|
return nil, errors.New("proto: not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: do not use.
|
||||||
|
func UnmarshalMessageSet([]byte, interface{}) error {
|
||||||
|
return errors.New("proto: not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: do not use.
|
||||||
|
func MarshalMessageSetJSON(interface{}) ([]byte, error) {
|
||||||
|
return nil, errors.New("proto: not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: do not use.
|
||||||
|
func UnmarshalMessageSetJSON([]byte, interface{}) error {
|
||||||
|
return errors.New("proto: not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: do not use.
|
||||||
|
func RegisterMessageSetType(Message, int32, string) {}
|
|
@ -246,7 +246,8 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
m1, m2 := e1.value, e2.value
|
m1 := extensionAsLegacyType(e1.value)
|
||||||
|
m2 := extensionAsLegacyType(e2.value)
|
||||||
|
|
||||||
if m1 == nil && m2 == nil {
|
if m1 == nil && m2 == nil {
|
||||||
// Both have only encoded form.
|
// Both have only encoded form.
|
||||||
|
|
|
@ -185,9 +185,25 @@ type Extension struct {
|
||||||
// extension will have only enc set. When such an extension is
|
// extension will have only enc set. When such an extension is
|
||||||
// accessed using GetExtension (or GetExtensions) desc and value
|
// accessed using GetExtension (or GetExtensions) desc and value
|
||||||
// will be set.
|
// will be set.
|
||||||
desc *ExtensionDesc
|
desc *ExtensionDesc
|
||||||
|
|
||||||
|
// value is a concrete value for the extension field. Let the type of
|
||||||
|
// desc.ExtensionType be the "API type" and the type of Extension.value
|
||||||
|
// be the "storage type". The API type and storage type are the same except:
|
||||||
|
// * For scalars (except []byte), the API type uses *T,
|
||||||
|
// while the storage type uses T.
|
||||||
|
// * For repeated fields, the API type uses []T, while the storage type
|
||||||
|
// uses *[]T.
|
||||||
|
//
|
||||||
|
// The reason for the divergence is so that the storage type more naturally
|
||||||
|
// matches what is expected of when retrieving the values through the
|
||||||
|
// protobuf reflection APIs.
|
||||||
|
//
|
||||||
|
// The value may only be populated if desc is also populated.
|
||||||
value interface{}
|
value interface{}
|
||||||
enc []byte
|
|
||||||
|
// enc is the raw bytes for the extension field.
|
||||||
|
enc []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRawExtension is for testing only.
|
// SetRawExtension is for testing only.
|
||||||
|
@ -334,7 +350,7 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
|
||||||
// descriptors with the same field number.
|
// descriptors with the same field number.
|
||||||
return nil, errors.New("proto: descriptor conflict")
|
return nil, errors.New("proto: descriptor conflict")
|
||||||
}
|
}
|
||||||
return e.value, nil
|
return extensionAsLegacyType(e.value), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if extension.ExtensionType == nil {
|
if extension.ExtensionType == nil {
|
||||||
|
@ -349,11 +365,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
|
||||||
|
|
||||||
// Remember the decoded version and drop the encoded version.
|
// Remember the decoded version and drop the encoded version.
|
||||||
// That way it is safe to mutate what we return.
|
// That way it is safe to mutate what we return.
|
||||||
e.value = v
|
e.value = extensionAsStorageType(v)
|
||||||
e.desc = extension
|
e.desc = extension
|
||||||
e.enc = nil
|
e.enc = nil
|
||||||
emap[extension.Field] = e
|
emap[extension.Field] = e
|
||||||
return e.value, nil
|
return extensionAsLegacyType(e.value), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultExtensionValue returns the default value for extension.
|
// defaultExtensionValue returns the default value for extension.
|
||||||
|
@ -488,7 +504,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error
|
||||||
}
|
}
|
||||||
typ := reflect.TypeOf(extension.ExtensionType)
|
typ := reflect.TypeOf(extension.ExtensionType)
|
||||||
if typ != reflect.TypeOf(value) {
|
if typ != reflect.TypeOf(value) {
|
||||||
return errors.New("proto: bad extension value type")
|
return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType)
|
||||||
}
|
}
|
||||||
// nil extension values need to be caught early, because the
|
// nil extension values need to be caught early, because the
|
||||||
// encoder can't distinguish an ErrNil due to a nil extension
|
// encoder can't distinguish an ErrNil due to a nil extension
|
||||||
|
@ -500,7 +516,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
extmap := epb.extensionsWrite()
|
extmap := epb.extensionsWrite()
|
||||||
extmap[extension.Field] = Extension{desc: extension, value: value}
|
extmap[extension.Field] = Extension{desc: extension, value: extensionAsStorageType(value)}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,3 +557,51 @@ func RegisterExtension(desc *ExtensionDesc) {
|
||||||
func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc {
|
func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc {
|
||||||
return extensionMaps[reflect.TypeOf(pb).Elem()]
|
return extensionMaps[reflect.TypeOf(pb).Elem()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extensionAsLegacyType converts an value in the storage type as the API type.
|
||||||
|
// See Extension.value.
|
||||||
|
func extensionAsLegacyType(v interface{}) interface{} {
|
||||||
|
switch rv := reflect.ValueOf(v); rv.Kind() {
|
||||||
|
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
|
||||||
|
// Represent primitive types as a pointer to the value.
|
||||||
|
rv2 := reflect.New(rv.Type())
|
||||||
|
rv2.Elem().Set(rv)
|
||||||
|
v = rv2.Interface()
|
||||||
|
case reflect.Ptr:
|
||||||
|
// Represent slice types as the value itself.
|
||||||
|
switch rv.Type().Elem().Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
if rv.IsNil() {
|
||||||
|
v = reflect.Zero(rv.Type().Elem()).Interface()
|
||||||
|
} else {
|
||||||
|
v = rv.Elem().Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// extensionAsStorageType converts an value in the API type as the storage type.
|
||||||
|
// See Extension.value.
|
||||||
|
func extensionAsStorageType(v interface{}) interface{} {
|
||||||
|
switch rv := reflect.ValueOf(v); rv.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
// Represent slice types as the value itself.
|
||||||
|
switch rv.Type().Elem().Kind() {
|
||||||
|
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
|
||||||
|
if rv.IsNil() {
|
||||||
|
v = reflect.Zero(rv.Type().Elem()).Interface()
|
||||||
|
} else {
|
||||||
|
v = rv.Elem().Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
// Represent slice types as a pointer to the value.
|
||||||
|
if rv.Type().Elem().Kind() != reflect.Uint8 {
|
||||||
|
rv2 := reflect.New(rv.Type())
|
||||||
|
rv2.Elem().Set(rv)
|
||||||
|
v = rv2.Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
|
@ -341,26 +341,6 @@ type Message interface {
|
||||||
ProtoMessage()
|
ProtoMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stats records allocation details about the protocol buffer encoders
|
|
||||||
// and decoders. Useful for tuning the library itself.
|
|
||||||
type Stats struct {
|
|
||||||
Emalloc uint64 // mallocs in encode
|
|
||||||
Dmalloc uint64 // mallocs in decode
|
|
||||||
Encode uint64 // number of encodes
|
|
||||||
Decode uint64 // number of decodes
|
|
||||||
Chit uint64 // number of cache hits
|
|
||||||
Cmiss uint64 // number of cache misses
|
|
||||||
Size uint64 // number of sizes
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set to true to enable stats collection.
|
|
||||||
const collectStats = false
|
|
||||||
|
|
||||||
var stats Stats
|
|
||||||
|
|
||||||
// GetStats returns a copy of the global Stats structure.
|
|
||||||
func GetStats() Stats { return stats }
|
|
||||||
|
|
||||||
// A Buffer is a buffer manager for marshaling and unmarshaling
|
// A Buffer is a buffer manager for marshaling and unmarshaling
|
||||||
// protocol buffers. It may be reused between invocations to
|
// protocol buffers. It may be reused between invocations to
|
||||||
// reduce memory usage. It is not necessary to use a Buffer;
|
// reduce memory usage. It is not necessary to use a Buffer;
|
||||||
|
@ -960,13 +940,19 @@ func isProto3Zero(v reflect.Value) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProtoPackageIsVersion2 is referenced from generated protocol buffer files
|
const (
|
||||||
// to assert that that code is compatible with this version of the proto package.
|
// ProtoPackageIsVersion3 is referenced from generated protocol buffer files
|
||||||
const ProtoPackageIsVersion2 = true
|
// to assert that that code is compatible with this version of the proto package.
|
||||||
|
ProtoPackageIsVersion3 = true
|
||||||
|
|
||||||
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
|
// ProtoPackageIsVersion2 is referenced from generated protocol buffer files
|
||||||
// to assert that that code is compatible with this version of the proto package.
|
// to assert that that code is compatible with this version of the proto package.
|
||||||
const ProtoPackageIsVersion1 = true
|
ProtoPackageIsVersion2 = true
|
||||||
|
|
||||||
|
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
|
||||||
|
// to assert that that code is compatible with this version of the proto package.
|
||||||
|
ProtoPackageIsVersion1 = true
|
||||||
|
)
|
||||||
|
|
||||||
// InternalMessageInfo is a type used internally by generated .pb.go files.
|
// InternalMessageInfo is a type used internally by generated .pb.go files.
|
||||||
// This type is not intended to be used by non-generated code.
|
// This type is not intended to be used by non-generated code.
|
||||||
|
|
|
@ -36,13 +36,7 @@ package proto
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
|
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
|
||||||
|
@ -145,46 +139,9 @@ func skipVarint(buf []byte) []byte {
|
||||||
return buf[i+1:]
|
return buf[i+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalMessageSet encodes the extension map represented by m in the message set wire format.
|
// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
||||||
// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
|
|
||||||
func MarshalMessageSet(exts interface{}) ([]byte, error) {
|
|
||||||
return marshalMessageSet(exts, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal.
|
|
||||||
func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) {
|
|
||||||
switch exts := exts.(type) {
|
|
||||||
case *XXX_InternalExtensions:
|
|
||||||
var u marshalInfo
|
|
||||||
siz := u.sizeMessageSet(exts)
|
|
||||||
b := make([]byte, 0, siz)
|
|
||||||
return u.appendMessageSet(b, exts, deterministic)
|
|
||||||
|
|
||||||
case map[int32]Extension:
|
|
||||||
// This is an old-style extension map.
|
|
||||||
// Wrap it in a new-style XXX_InternalExtensions.
|
|
||||||
ie := XXX_InternalExtensions{
|
|
||||||
p: &struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
extensionMap map[int32]Extension
|
|
||||||
}{
|
|
||||||
extensionMap: exts,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var u marshalInfo
|
|
||||||
siz := u.sizeMessageSet(&ie)
|
|
||||||
b := make([]byte, 0, siz)
|
|
||||||
return u.appendMessageSet(b, &ie, deterministic)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, errors.New("proto: not an extension map")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
|
||||||
// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
func UnmarshalMessageSet(buf []byte, exts interface{}) error {
|
func unmarshalMessageSet(buf []byte, exts interface{}) error {
|
||||||
var m map[int32]Extension
|
var m map[int32]Extension
|
||||||
switch exts := exts.(type) {
|
switch exts := exts.(type) {
|
||||||
case *XXX_InternalExtensions:
|
case *XXX_InternalExtensions:
|
||||||
|
@ -222,93 +179,3 @@ func UnmarshalMessageSet(buf []byte, exts interface{}) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
|
|
||||||
// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
|
|
||||||
func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
|
|
||||||
var m map[int32]Extension
|
|
||||||
switch exts := exts.(type) {
|
|
||||||
case *XXX_InternalExtensions:
|
|
||||||
var mu sync.Locker
|
|
||||||
m, mu = exts.extensionsRead()
|
|
||||||
if m != nil {
|
|
||||||
// Keep the extensions map locked until we're done marshaling to prevent
|
|
||||||
// races between marshaling and unmarshaling the lazily-{en,de}coded
|
|
||||||
// values.
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
}
|
|
||||||
case map[int32]Extension:
|
|
||||||
m = exts
|
|
||||||
default:
|
|
||||||
return nil, errors.New("proto: not an extension map")
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
b.WriteByte('{')
|
|
||||||
|
|
||||||
// Process the map in key order for deterministic output.
|
|
||||||
ids := make([]int32, 0, len(m))
|
|
||||||
for id := range m {
|
|
||||||
ids = append(ids, id)
|
|
||||||
}
|
|
||||||
sort.Sort(int32Slice(ids)) // int32Slice defined in text.go
|
|
||||||
|
|
||||||
for i, id := range ids {
|
|
||||||
ext := m[id]
|
|
||||||
msd, ok := messageSetMap[id]
|
|
||||||
if !ok {
|
|
||||||
// Unknown type; we can't render it, so skip it.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if i > 0 && b.Len() > 1 {
|
|
||||||
b.WriteByte(',')
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(&b, `"[%s]":`, msd.name)
|
|
||||||
|
|
||||||
x := ext.value
|
|
||||||
if x == nil {
|
|
||||||
x = reflect.New(msd.t.Elem()).Interface()
|
|
||||||
if err := Unmarshal(ext.enc, x.(Message)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d, err := json.Marshal(x)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
b.Write(d)
|
|
||||||
}
|
|
||||||
b.WriteByte('}')
|
|
||||||
return b.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
|
|
||||||
// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
|
|
||||||
func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error {
|
|
||||||
// Common-case fast path.
|
|
||||||
if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is fairly tricky, and it's not clear that it is needed.
|
|
||||||
return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// A global registry of types that can be used in a MessageSet.
|
|
||||||
|
|
||||||
var messageSetMap = make(map[int32]messageSetDesc)
|
|
||||||
|
|
||||||
type messageSetDesc struct {
|
|
||||||
t reflect.Type // pointer to struct
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterMessageSetType is called from the generated code.
|
|
||||||
func RegisterMessageSetType(m Message, fieldNum int32, name string) {
|
|
||||||
messageSetMap[fieldNum] = messageSetDesc{
|
|
||||||
t: reflect.TypeOf(m),
|
|
||||||
name: name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -79,10 +79,13 @@ func toPointer(i *Message) pointer {
|
||||||
|
|
||||||
// toAddrPointer converts an interface to a pointer that points to
|
// toAddrPointer converts an interface to a pointer that points to
|
||||||
// the interface data.
|
// the interface data.
|
||||||
func toAddrPointer(i *interface{}, isptr bool) pointer {
|
func toAddrPointer(i *interface{}, isptr, deref bool) pointer {
|
||||||
v := reflect.ValueOf(*i)
|
v := reflect.ValueOf(*i)
|
||||||
u := reflect.New(v.Type())
|
u := reflect.New(v.Type())
|
||||||
u.Elem().Set(v)
|
u.Elem().Set(v)
|
||||||
|
if deref {
|
||||||
|
u = u.Elem()
|
||||||
|
}
|
||||||
return pointer{v: u}
|
return pointer{v: u}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,16 +85,21 @@ func toPointer(i *Message) pointer {
|
||||||
|
|
||||||
// toAddrPointer converts an interface to a pointer that points to
|
// toAddrPointer converts an interface to a pointer that points to
|
||||||
// the interface data.
|
// the interface data.
|
||||||
func toAddrPointer(i *interface{}, isptr bool) pointer {
|
func toAddrPointer(i *interface{}, isptr, deref bool) (p pointer) {
|
||||||
// Super-tricky - read or get the address of data word of interface value.
|
// Super-tricky - read or get the address of data word of interface value.
|
||||||
if isptr {
|
if isptr {
|
||||||
// The interface is of pointer type, thus it is a direct interface.
|
// The interface is of pointer type, thus it is a direct interface.
|
||||||
// The data word is the pointer data itself. We take its address.
|
// The data word is the pointer data itself. We take its address.
|
||||||
return pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)}
|
p = pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)}
|
||||||
|
} else {
|
||||||
|
// The interface is not of pointer type. The data word is the pointer
|
||||||
|
// to the data.
|
||||||
|
p = pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
|
||||||
}
|
}
|
||||||
// The interface is not of pointer type. The data word is the pointer
|
if deref {
|
||||||
// to the data.
|
p.p = *(*unsafe.Pointer)(p.p)
|
||||||
return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
|
}
|
||||||
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// valToPointer converts v to a pointer. v must be of pointer type.
|
// valToPointer converts v to a pointer. v must be of pointer type.
|
||||||
|
|
|
@ -334,9 +334,6 @@ func GetProperties(t reflect.Type) *StructProperties {
|
||||||
sprop, ok := propertiesMap[t]
|
sprop, ok := propertiesMap[t]
|
||||||
propertiesMu.RUnlock()
|
propertiesMu.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
if collectStats {
|
|
||||||
stats.Chit++
|
|
||||||
}
|
|
||||||
return sprop
|
return sprop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,17 +343,20 @@ func GetProperties(t reflect.Type) *StructProperties {
|
||||||
return sprop
|
return sprop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
oneofFuncsIface interface {
|
||||||
|
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
|
||||||
|
}
|
||||||
|
oneofWrappersIface interface {
|
||||||
|
XXX_OneofWrappers() []interface{}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// getPropertiesLocked requires that propertiesMu is held.
|
// getPropertiesLocked requires that propertiesMu is held.
|
||||||
func getPropertiesLocked(t reflect.Type) *StructProperties {
|
func getPropertiesLocked(t reflect.Type) *StructProperties {
|
||||||
if prop, ok := propertiesMap[t]; ok {
|
if prop, ok := propertiesMap[t]; ok {
|
||||||
if collectStats {
|
|
||||||
stats.Chit++
|
|
||||||
}
|
|
||||||
return prop
|
return prop
|
||||||
}
|
}
|
||||||
if collectStats {
|
|
||||||
stats.Cmiss++
|
|
||||||
}
|
|
||||||
|
|
||||||
prop := new(StructProperties)
|
prop := new(StructProperties)
|
||||||
// in case of recursive protos, fill this in now.
|
// in case of recursive protos, fill this in now.
|
||||||
|
@ -391,13 +391,14 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
|
||||||
// Re-order prop.order.
|
// Re-order prop.order.
|
||||||
sort.Sort(prop)
|
sort.Sort(prop)
|
||||||
|
|
||||||
type oneofMessage interface {
|
var oots []interface{}
|
||||||
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
|
switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
|
||||||
|
case oneofFuncsIface:
|
||||||
|
_, _, _, oots = m.XXX_OneofFuncs()
|
||||||
|
case oneofWrappersIface:
|
||||||
|
oots = m.XXX_OneofWrappers()
|
||||||
}
|
}
|
||||||
if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
|
if len(oots) > 0 {
|
||||||
var oots []interface{}
|
|
||||||
_, _, _, oots = om.XXX_OneofFuncs()
|
|
||||||
|
|
||||||
// Interpret oneof metadata.
|
// Interpret oneof metadata.
|
||||||
prop.OneofTypes = make(map[string]*OneofProperties)
|
prop.OneofTypes = make(map[string]*OneofProperties)
|
||||||
for _, oot := range oots {
|
for _, oot := range oots {
|
||||||
|
|
|
@ -87,6 +87,7 @@ type marshalElemInfo struct {
|
||||||
sizer sizer
|
sizer sizer
|
||||||
marshaler marshaler
|
marshaler marshaler
|
||||||
isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only)
|
isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only)
|
||||||
|
deref bool // dereference the pointer before operating on it; implies isptr
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -320,8 +321,11 @@ func (u *marshalInfo) computeMarshalInfo() {
|
||||||
|
|
||||||
// get oneof implementers
|
// get oneof implementers
|
||||||
var oneofImplementers []interface{}
|
var oneofImplementers []interface{}
|
||||||
if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
|
switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
|
||||||
|
case oneofFuncsIface:
|
||||||
_, _, _, oneofImplementers = m.XXX_OneofFuncs()
|
_, _, _, oneofImplementers = m.XXX_OneofFuncs()
|
||||||
|
case oneofWrappersIface:
|
||||||
|
oneofImplementers = m.XXX_OneofWrappers()
|
||||||
}
|
}
|
||||||
|
|
||||||
n := t.NumField()
|
n := t.NumField()
|
||||||
|
@ -407,13 +411,22 @@ func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo {
|
||||||
panic("tag is not an integer")
|
panic("tag is not an integer")
|
||||||
}
|
}
|
||||||
wt := wiretype(tags[0])
|
wt := wiretype(tags[0])
|
||||||
|
if t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct {
|
||||||
|
t = t.Elem()
|
||||||
|
}
|
||||||
sizer, marshaler := typeMarshaler(t, tags, false, false)
|
sizer, marshaler := typeMarshaler(t, tags, false, false)
|
||||||
|
var deref bool
|
||||||
|
if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
|
||||||
|
t = reflect.PtrTo(t)
|
||||||
|
deref = true
|
||||||
|
}
|
||||||
e = &marshalElemInfo{
|
e = &marshalElemInfo{
|
||||||
wiretag: uint64(tag)<<3 | wt,
|
wiretag: uint64(tag)<<3 | wt,
|
||||||
tagsize: SizeVarint(uint64(tag) << 3),
|
tagsize: SizeVarint(uint64(tag) << 3),
|
||||||
sizer: sizer,
|
sizer: sizer,
|
||||||
marshaler: marshaler,
|
marshaler: marshaler,
|
||||||
isptr: t.Kind() == reflect.Ptr,
|
isptr: t.Kind() == reflect.Ptr,
|
||||||
|
deref: deref,
|
||||||
}
|
}
|
||||||
|
|
||||||
// update cache
|
// update cache
|
||||||
|
@ -448,7 +461,7 @@ func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) {
|
||||||
|
|
||||||
func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) {
|
func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) {
|
||||||
fi.field = toField(f)
|
fi.field = toField(f)
|
||||||
fi.wiretag = 1<<31 - 1 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire.
|
fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire.
|
||||||
fi.isPointer = true
|
fi.isPointer = true
|
||||||
fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f)
|
fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f)
|
||||||
fi.oneofElems = make(map[reflect.Type]*marshalElemInfo)
|
fi.oneofElems = make(map[reflect.Type]*marshalElemInfo)
|
||||||
|
@ -476,10 +489,6 @@ func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type oneofMessage interface {
|
|
||||||
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// wiretype returns the wire encoding of the type.
|
// wiretype returns the wire encoding of the type.
|
||||||
func wiretype(encoding string) uint64 {
|
func wiretype(encoding string) uint64 {
|
||||||
switch encoding {
|
switch encoding {
|
||||||
|
@ -2310,8 +2319,8 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
|
||||||
for _, k := range m.MapKeys() {
|
for _, k := range m.MapKeys() {
|
||||||
ki := k.Interface()
|
ki := k.Interface()
|
||||||
vi := m.MapIndex(k).Interface()
|
vi := m.MapIndex(k).Interface()
|
||||||
kaddr := toAddrPointer(&ki, false) // pointer to key
|
kaddr := toAddrPointer(&ki, false, false) // pointer to key
|
||||||
vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
|
vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value
|
||||||
siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
|
siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
|
||||||
n += siz + SizeVarint(uint64(siz)) + tagsize
|
n += siz + SizeVarint(uint64(siz)) + tagsize
|
||||||
}
|
}
|
||||||
|
@ -2329,8 +2338,8 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
ki := k.Interface()
|
ki := k.Interface()
|
||||||
vi := m.MapIndex(k).Interface()
|
vi := m.MapIndex(k).Interface()
|
||||||
kaddr := toAddrPointer(&ki, false) // pointer to key
|
kaddr := toAddrPointer(&ki, false, false) // pointer to key
|
||||||
vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
|
vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value
|
||||||
b = appendVarint(b, tag)
|
b = appendVarint(b, tag)
|
||||||
siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
|
siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
|
||||||
b = appendVarint(b, uint64(siz))
|
b = appendVarint(b, uint64(siz))
|
||||||
|
@ -2399,7 +2408,7 @@ func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int {
|
||||||
// the last time this function was called.
|
// the last time this function was called.
|
||||||
ei := u.getExtElemInfo(e.desc)
|
ei := u.getExtElemInfo(e.desc)
|
||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr, ei.deref)
|
||||||
n += ei.sizer(p, ei.tagsize)
|
n += ei.sizer(p, ei.tagsize)
|
||||||
}
|
}
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
|
@ -2434,7 +2443,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
|
||||||
|
|
||||||
ei := u.getExtElemInfo(e.desc)
|
ei := u.getExtElemInfo(e.desc)
|
||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr, ei.deref)
|
||||||
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
||||||
if !nerr.Merge(err) {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
|
@ -2465,7 +2474,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
|
||||||
|
|
||||||
ei := u.getExtElemInfo(e.desc)
|
ei := u.getExtElemInfo(e.desc)
|
||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr, ei.deref)
|
||||||
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
||||||
if !nerr.Merge(err) {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
|
@ -2510,7 +2519,7 @@ func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int {
|
||||||
|
|
||||||
ei := u.getExtElemInfo(e.desc)
|
ei := u.getExtElemInfo(e.desc)
|
||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr, ei.deref)
|
||||||
n += ei.sizer(p, 1) // message, tag = 3 (size=1)
|
n += ei.sizer(p, 1) // message, tag = 3 (size=1)
|
||||||
}
|
}
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
|
@ -2553,7 +2562,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
|
||||||
|
|
||||||
ei := u.getExtElemInfo(e.desc)
|
ei := u.getExtElemInfo(e.desc)
|
||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr, ei.deref)
|
||||||
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
||||||
if !nerr.Merge(err) {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
|
@ -2591,7 +2600,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
|
||||||
|
|
||||||
ei := u.getExtElemInfo(e.desc)
|
ei := u.getExtElemInfo(e.desc)
|
||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr, ei.deref)
|
||||||
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
||||||
b = append(b, 1<<3|WireEndGroup)
|
b = append(b, 1<<3|WireEndGroup)
|
||||||
if !nerr.Merge(err) {
|
if !nerr.Merge(err) {
|
||||||
|
@ -2621,7 +2630,7 @@ func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int {
|
||||||
|
|
||||||
ei := u.getExtElemInfo(e.desc)
|
ei := u.getExtElemInfo(e.desc)
|
||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr, ei.deref)
|
||||||
n += ei.sizer(p, ei.tagsize)
|
n += ei.sizer(p, ei.tagsize)
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
|
@ -2656,7 +2665,7 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ
|
||||||
|
|
||||||
ei := u.getExtElemInfo(e.desc)
|
ei := u.getExtElemInfo(e.desc)
|
||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr, ei.deref)
|
||||||
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
||||||
if !nerr.Merge(err) {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
|
|
|
@ -136,7 +136,7 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
|
||||||
u.computeUnmarshalInfo()
|
u.computeUnmarshalInfo()
|
||||||
}
|
}
|
||||||
if u.isMessageSet {
|
if u.isMessageSet {
|
||||||
return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
|
return unmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
|
||||||
}
|
}
|
||||||
var reqMask uint64 // bitmask of required fields we've seen.
|
var reqMask uint64 // bitmask of required fields we've seen.
|
||||||
var errLater error
|
var errLater error
|
||||||
|
@ -362,46 +362,48 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find any types associated with oneof fields.
|
// Find any types associated with oneof fields.
|
||||||
// TODO: XXX_OneofFuncs returns more info than we need. Get rid of some of it?
|
var oneofImplementers []interface{}
|
||||||
fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("XXX_OneofFuncs")
|
switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
|
||||||
if fn.IsValid() {
|
case oneofFuncsIface:
|
||||||
res := fn.Call(nil)[3] // last return value from XXX_OneofFuncs: []interface{}
|
_, _, _, oneofImplementers = m.XXX_OneofFuncs()
|
||||||
for i := res.Len() - 1; i >= 0; i-- {
|
case oneofWrappersIface:
|
||||||
v := res.Index(i) // interface{}
|
oneofImplementers = m.XXX_OneofWrappers()
|
||||||
tptr := reflect.ValueOf(v.Interface()).Type() // *Msg_X
|
}
|
||||||
typ := tptr.Elem() // Msg_X
|
for _, v := range oneofImplementers {
|
||||||
|
tptr := reflect.TypeOf(v) // *Msg_X
|
||||||
|
typ := tptr.Elem() // Msg_X
|
||||||
|
|
||||||
f := typ.Field(0) // oneof implementers have one field
|
f := typ.Field(0) // oneof implementers have one field
|
||||||
baseUnmarshal := fieldUnmarshaler(&f)
|
baseUnmarshal := fieldUnmarshaler(&f)
|
||||||
tags := strings.Split(f.Tag.Get("protobuf"), ",")
|
tags := strings.Split(f.Tag.Get("protobuf"), ",")
|
||||||
fieldNum, err := strconv.Atoi(tags[1])
|
fieldNum, err := strconv.Atoi(tags[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("protobuf tag field not an integer: " + tags[1])
|
panic("protobuf tag field not an integer: " + tags[1])
|
||||||
}
|
}
|
||||||
var name string
|
var name string
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
if strings.HasPrefix(tag, "name=") {
|
if strings.HasPrefix(tag, "name=") {
|
||||||
name = strings.TrimPrefix(tag, "name=")
|
name = strings.TrimPrefix(tag, "name=")
|
||||||
break
|
break
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the oneof field that this struct implements.
|
|
||||||
// Might take O(n^2) to process all of the oneofs, but who cares.
|
|
||||||
for _, of := range oneofFields {
|
|
||||||
if tptr.Implements(of.ityp) {
|
|
||||||
// We have found the corresponding interface for this struct.
|
|
||||||
// That lets us know where this struct should be stored
|
|
||||||
// when we encounter it during unmarshaling.
|
|
||||||
unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal)
|
|
||||||
u.setTag(fieldNum, of.field, unmarshal, 0, name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the oneof field that this struct implements.
|
||||||
|
// Might take O(n^2) to process all of the oneofs, but who cares.
|
||||||
|
for _, of := range oneofFields {
|
||||||
|
if tptr.Implements(of.ityp) {
|
||||||
|
// We have found the corresponding interface for this struct.
|
||||||
|
// That lets us know where this struct should be stored
|
||||||
|
// when we encounter it during unmarshaling.
|
||||||
|
unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal)
|
||||||
|
u.setTag(fieldNum, of.field, unmarshal, 0, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get extension ranges, if any.
|
// Get extension ranges, if any.
|
||||||
fn = reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray")
|
fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray")
|
||||||
if fn.IsValid() {
|
if fn.IsValid() {
|
||||||
if !u.extensions.IsValid() && !u.oldExtensions.IsValid() {
|
if !u.extensions.IsValid() && !u.oldExtensions.IsValid() {
|
||||||
panic("a message with extensions, but no extensions field in " + t.Name())
|
panic("a message with extensions, but no extensions field in " + t.Name())
|
||||||
|
@ -1948,7 +1950,7 @@ func encodeVarint(b []byte, x uint64) []byte {
|
||||||
// If there is an error, it returns 0,0.
|
// If there is an error, it returns 0,0.
|
||||||
func decodeVarint(b []byte) (uint64, int) {
|
func decodeVarint(b []byte) (uint64, int) {
|
||||||
var x, y uint64
|
var x, y uint64
|
||||||
if len(b) <= 0 {
|
if len(b) == 0 {
|
||||||
goto bad
|
goto bad
|
||||||
}
|
}
|
||||||
x = uint64(b[0])
|
x = uint64(b[0])
|
||||||
|
|
|
@ -26,6 +26,7 @@ The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
|
||||||
We thank all the authors who provided code to this library:
|
We thank all the authors who provided code to this library:
|
||||||
|
|
||||||
* Felix Kollmann
|
* Felix Kollmann
|
||||||
|
* Nicolas Perraut
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
11
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
generated
vendored
Normal file
11
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// +build linux darwin
|
||||||
|
|
||||||
|
package sequences
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EnableVirtualTerminalProcessing(stream uintptr, enable bool) error {
|
||||||
|
return fmt.Errorf("windows only package")
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/mattn/go-xmlrpc
|
||||||
|
|
||||||
|
go 1.10
|
|
@ -1,52 +1,21 @@
|
||||||
language: go
|
language: go
|
||||||
go_import_path: github.com/sirupsen/logrus
|
go_import_path: github.com/sirupsen/logrus
|
||||||
|
git:
|
||||||
|
depth: 1
|
||||||
env:
|
env:
|
||||||
- GOMAXPROCS=4 GORACE=halt_on_error=1
|
- GO111MODULE=on
|
||||||
|
- GO111MODULE=off
|
||||||
|
go: [ 1.10.x, 1.11.x, 1.12.x ]
|
||||||
|
os: [ linux, osx, windows ]
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
exclude:
|
||||||
- go: 1.10.x
|
- env: GO111MODULE=on
|
||||||
install:
|
go: 1.10.x
|
||||||
- go get github.com/stretchr/testify/assert
|
install:
|
||||||
- go get golang.org/x/crypto/ssh/terminal
|
- if [[ "$GO111MODULE" == "on" ]]; then go mod download; fi
|
||||||
- go get golang.org/x/sys/unix
|
- if [[ "$GO111MODULE" == "off" ]]; then go get github.com/stretchr/testify/assert golang.org/x/sys/unix github.com/konsorten/go-windows-terminal-sequences; fi
|
||||||
- go get golang.org/x/sys/windows
|
script:
|
||||||
script:
|
- export GOMAXPROCS=4
|
||||||
- go test -race -v ./...
|
- export GORACE=halt_on_error=1
|
||||||
- go: 1.11.x
|
- go test -race -v ./...
|
||||||
env: GO111MODULE=on
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then go test -race -v -tags appengine ./... ; fi
|
||||||
install:
|
|
||||||
- go mod download
|
|
||||||
script:
|
|
||||||
- go test -race -v ./...
|
|
||||||
- go: 1.11.x
|
|
||||||
env: GO111MODULE=off
|
|
||||||
install:
|
|
||||||
- go get github.com/stretchr/testify/assert
|
|
||||||
- go get golang.org/x/crypto/ssh/terminal
|
|
||||||
- go get golang.org/x/sys/unix
|
|
||||||
- go get golang.org/x/sys/windows
|
|
||||||
script:
|
|
||||||
- go test -race -v ./...
|
|
||||||
- go: 1.10.x
|
|
||||||
install:
|
|
||||||
- go get github.com/stretchr/testify/assert
|
|
||||||
- go get golang.org/x/crypto/ssh/terminal
|
|
||||||
- go get golang.org/x/sys/unix
|
|
||||||
- go get golang.org/x/sys/windows
|
|
||||||
script:
|
|
||||||
- go test -race -v -tags appengine ./...
|
|
||||||
- go: 1.11.x
|
|
||||||
env: GO111MODULE=on
|
|
||||||
install:
|
|
||||||
- go mod download
|
|
||||||
script:
|
|
||||||
- go test -race -v -tags appengine ./...
|
|
||||||
- go: 1.11.x
|
|
||||||
env: GO111MODULE=off
|
|
||||||
install:
|
|
||||||
- go get github.com/stretchr/testify/assert
|
|
||||||
- go get golang.org/x/crypto/ssh/terminal
|
|
||||||
- go get golang.org/x/sys/unix
|
|
||||||
- go get golang.org/x/sys/windows
|
|
||||||
script:
|
|
||||||
- go test -race -v -tags appengine ./...
|
|
||||||
|
|
|
@ -1,3 +1,36 @@
|
||||||
|
# 1.4.1
|
||||||
|
This new release introduces:
|
||||||
|
* Enhance TextFormatter to not print caller information when they are empty (#944)
|
||||||
|
* Remove dependency on golang.org/x/crypto (#932, #943)
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
* Fix Entry.WithContext method to return a copy of the initial entry (#941)
|
||||||
|
|
||||||
|
# 1.4.0
|
||||||
|
This new release introduces:
|
||||||
|
* Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848).
|
||||||
|
* Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter (#909, #911)
|
||||||
|
* Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919).
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
* Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893).
|
||||||
|
* Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903)
|
||||||
|
* Fix infinite recursion on unknown `Level.String()` (#907)
|
||||||
|
* Fix race condition in `getCaller` (#916).
|
||||||
|
|
||||||
|
|
||||||
|
# 1.3.0
|
||||||
|
This new release introduces:
|
||||||
|
* Log, Logf, Logln functions for Logger and Entry that take a Level
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
* Building prometheus node_exporter on AIX (#840)
|
||||||
|
* Race condition in TextFormatter (#468)
|
||||||
|
* Travis CI import path (#868)
|
||||||
|
* Remove coloured output on Windows (#862)
|
||||||
|
* Pointer to func as field in JSONFormatter (#870)
|
||||||
|
* Properly marshal Levels (#873)
|
||||||
|
|
||||||
# 1.2.0
|
# 1.2.0
|
||||||
This new release introduces:
|
This new release introduces:
|
||||||
* A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
|
* A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
|
||||||
|
|
|
@ -365,6 +365,7 @@ Third party logging formatters:
|
||||||
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
||||||
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
||||||
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
|
* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
|
||||||
|
|
||||||
You can define your formatter by implementing the `Formatter` interface,
|
You can define your formatter by implementing the `Formatter` interface,
|
||||||
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||||
|
|
|
@ -51,9 +51,9 @@ func Exit(code int) {
|
||||||
os.Exit(code)
|
os.Exit(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
|
// RegisterExitHandler appends a Logrus Exit handler to the list of handlers,
|
||||||
// all handlers. The handlers will also be invoked when any Fatal log entry is
|
// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
|
||||||
// made.
|
// any Fatal log entry is made.
|
||||||
//
|
//
|
||||||
// This method is useful when a caller wishes to use logrus to log a fatal
|
// This method is useful when a caller wishes to use logrus to log a fatal
|
||||||
// message but also needs to gracefully shutdown. An example usecase could be
|
// message but also needs to gracefully shutdown. An example usecase could be
|
||||||
|
@ -62,3 +62,15 @@ func Exit(code int) {
|
||||||
func RegisterExitHandler(handler func()) {
|
func RegisterExitHandler(handler func()) {
|
||||||
handlers = append(handlers, handler)
|
handlers = append(handlers, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeferExitHandler prepends a Logrus Exit handler to the list of handlers,
|
||||||
|
// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
|
||||||
|
// any Fatal log entry is made.
|
||||||
|
//
|
||||||
|
// This method is useful when a caller wishes to use logrus to log a fatal
|
||||||
|
// message but also needs to gracefully shutdown. An example usecase could be
|
||||||
|
// closing database connections, or sending a alert that the application is
|
||||||
|
// closing.
|
||||||
|
func DeferExitHandler(handler func()) {
|
||||||
|
handlers = append([]func(){handler}, handlers...)
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package logrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -69,6 +70,9 @@ type Entry struct {
|
||||||
// When formatter is called in entry.log(), a Buffer may be set to entry
|
// When formatter is called in entry.log(), a Buffer may be set to entry
|
||||||
Buffer *bytes.Buffer
|
Buffer *bytes.Buffer
|
||||||
|
|
||||||
|
// Contains the context set by the user. Useful for hook processing etc.
|
||||||
|
Context context.Context
|
||||||
|
|
||||||
// err may contain a field formatting error
|
// err may contain a field formatting error
|
||||||
err string
|
err string
|
||||||
}
|
}
|
||||||
|
@ -97,6 +101,11 @@ func (entry *Entry) WithError(err error) *Entry {
|
||||||
return entry.WithField(ErrorKey, err)
|
return entry.WithField(ErrorKey, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a context to the Entry.
|
||||||
|
func (entry *Entry) WithContext(ctx context.Context) *Entry {
|
||||||
|
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: entry.Time, err: entry.err, Context: ctx}
|
||||||
|
}
|
||||||
|
|
||||||
// Add a single field to the Entry.
|
// Add a single field to the Entry.
|
||||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||||
return entry.WithFields(Fields{key: value})
|
return entry.WithFields(Fields{key: value})
|
||||||
|
@ -130,12 +139,12 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr}
|
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overrides the time of the Entry.
|
// Overrides the time of the Entry.
|
||||||
func (entry *Entry) WithTime(t time.Time) *Entry {
|
func (entry *Entry) WithTime(t time.Time) *Entry {
|
||||||
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err}
|
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err, Context: entry.Context}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPackageName reduces a fully qualified function name to the package name
|
// getPackageName reduces a fully qualified function name to the package name
|
||||||
|
@ -156,20 +165,23 @@ func getPackageName(f string) string {
|
||||||
|
|
||||||
// getCaller retrieves the name of the first non-logrus calling function
|
// getCaller retrieves the name of the first non-logrus calling function
|
||||||
func getCaller() *runtime.Frame {
|
func getCaller() *runtime.Frame {
|
||||||
|
|
||||||
|
// cache this package's fully-qualified name
|
||||||
|
callerInitOnce.Do(func() {
|
||||||
|
pcs := make([]uintptr, 2)
|
||||||
|
_ = runtime.Callers(0, pcs)
|
||||||
|
logrusPackage = getPackageName(runtime.FuncForPC(pcs[1]).Name())
|
||||||
|
|
||||||
|
// now that we have the cache, we can skip a minimum count of known-logrus functions
|
||||||
|
// XXX this is dubious, the number of frames may vary
|
||||||
|
minimumCallerDepth = knownLogrusFrames
|
||||||
|
})
|
||||||
|
|
||||||
// Restrict the lookback frames to avoid runaway lookups
|
// Restrict the lookback frames to avoid runaway lookups
|
||||||
pcs := make([]uintptr, maximumCallerDepth)
|
pcs := make([]uintptr, maximumCallerDepth)
|
||||||
depth := runtime.Callers(minimumCallerDepth, pcs)
|
depth := runtime.Callers(minimumCallerDepth, pcs)
|
||||||
frames := runtime.CallersFrames(pcs[:depth])
|
frames := runtime.CallersFrames(pcs[:depth])
|
||||||
|
|
||||||
// cache this package's fully-qualified name
|
|
||||||
callerInitOnce.Do(func() {
|
|
||||||
logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name())
|
|
||||||
|
|
||||||
// now that we have the cache, we can skip a minimum count of known-logrus functions
|
|
||||||
// XXX this is dubious, the number of frames may vary store an entry in a logger interface
|
|
||||||
minimumCallerDepth = knownLogrusFrames
|
|
||||||
})
|
|
||||||
|
|
||||||
for f, again := frames.Next(); again; f, again = frames.Next() {
|
for f, again := frames.Next(); again; f, again = frames.Next() {
|
||||||
pkg := getPackageName(f.Function)
|
pkg := getPackageName(f.Function)
|
||||||
|
|
||||||
|
@ -298,7 +310,9 @@ func (entry *Entry) Panic(args ...interface{}) {
|
||||||
// Entry Printf family functions
|
// Entry Printf family functions
|
||||||
|
|
||||||
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
|
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
|
||||||
entry.Log(level, fmt.Sprintf(format, args...))
|
if entry.Logger.IsLevelEnabled(level) {
|
||||||
|
entry.Log(level, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Tracef(format string, args ...interface{}) {
|
func (entry *Entry) Tracef(format string, args ...interface{}) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -55,6 +56,11 @@ func WithError(err error) *Entry {
|
||||||
return std.WithField(ErrorKey, err)
|
return std.WithField(ErrorKey, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithContext creates an entry from the standard logger and adds a context to it.
|
||||||
|
func WithContext(ctx context.Context) *Entry {
|
||||||
|
return std.WithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// WithField creates an entry from the standard logger and adds a field to
|
// WithField creates an entry from the standard logger and adds a field to
|
||||||
// it. If you want multiple fields, use `WithFields`.
|
// it. If you want multiple fields, use `WithFields`.
|
||||||
//
|
//
|
||||||
|
|
|
@ -6,6 +6,5 @@ require (
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/stretchr/objx v0.1.1 // indirect
|
github.com/stretchr/objx v0.1.1 // indirect
|
||||||
github.com/stretchr/testify v1.2.2
|
github.com/stretchr/testify v1.2.2
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,7 +9,5 @@ github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fieldKey string
|
type fieldKey string
|
||||||
|
@ -42,6 +43,12 @@ type JSONFormatter struct {
|
||||||
// }
|
// }
|
||||||
FieldMap FieldMap
|
FieldMap FieldMap
|
||||||
|
|
||||||
|
// CallerPrettyfier can be set by the user to modify the content
|
||||||
|
// of the function and file keys in the json data when ReportCaller is
|
||||||
|
// activated. If any of the returned value is the empty string the
|
||||||
|
// corresponding key will be removed from json fields.
|
||||||
|
CallerPrettyfier func(*runtime.Frame) (function string, file string)
|
||||||
|
|
||||||
// PrettyPrint will indent all json logs
|
// PrettyPrint will indent all json logs
|
||||||
PrettyPrint bool
|
PrettyPrint bool
|
||||||
}
|
}
|
||||||
|
@ -82,8 +89,17 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
||||||
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
||||||
if entry.HasCaller() {
|
if entry.HasCaller() {
|
||||||
data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
|
funcVal := entry.Caller.Function
|
||||||
data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
|
if f.CallerPrettyfier != nil {
|
||||||
|
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||||
|
}
|
||||||
|
if funcVal != "" {
|
||||||
|
data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal
|
||||||
|
}
|
||||||
|
if fileVal != "" {
|
||||||
|
data[f.FieldMap.resolve(FieldKeyFile)] = fileVal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var b *bytes.Buffer
|
var b *bytes.Buffer
|
||||||
|
@ -98,7 +114,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
encoder.SetIndent("", " ")
|
encoder.SetIndent("", " ")
|
||||||
}
|
}
|
||||||
if err := encoder.Encode(data); err != nil {
|
if err := encoder.Encode(data); err != nil {
|
||||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -124,6 +125,13 @@ func (logger *Logger) WithError(err error) *Entry {
|
||||||
return entry.WithError(err)
|
return entry.WithError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a context to the log entry.
|
||||||
|
func (logger *Logger) WithContext(ctx context.Context) *Entry {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
defer logger.releaseEntry(entry)
|
||||||
|
return entry.WithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// Overrides the time of the log entry.
|
// Overrides the time of the log entry.
|
||||||
func (logger *Logger) WithTime(t time.Time) *Entry {
|
func (logger *Logger) WithTime(t time.Time) *Entry {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
|
@ -200,7 +208,7 @@ func (logger *Logger) Info(args ...interface{}) {
|
||||||
|
|
||||||
func (logger *Logger) Print(args ...interface{}) {
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
entry.Info(args...)
|
entry.Print(args...)
|
||||||
logger.releaseEntry(entry)
|
logger.releaseEntry(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +264,7 @@ func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warningln(args ...interface{}) {
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
logger.Warn(args...)
|
logger.Warnln(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Errorln(args ...interface{}) {
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (level Level) MarshalText() ([]byte, error) {
|
||||||
return []byte("panic"), nil
|
return []byte("panic"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("not a valid lorus level %q", level)
|
return nil, fmt.Errorf("not a valid logrus level %d", level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A constant exposing all logging levels
|
// A constant exposing all logging levels
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
// +build !appengine,!js,!windows,aix
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// +build darwin dragonfly freebsd netbsd openbsd
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
const ioctlReadTermios = unix.TIOCGETA
|
||||||
|
|
||||||
|
func isTerminal(fd int) bool {
|
||||||
|
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
// +build !appengine,!js,!windows,!aix
|
// +build !appengine,!js,!windows
|
||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
switch v := w.(type) {
|
switch v := w.(type) {
|
||||||
case *os.File:
|
case *os.File:
|
||||||
return terminal.IsTerminal(int(v.Fd()))
|
return isTerminal(int(v.Fd()))
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// +build linux aix
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
const ioctlReadTermios = unix.TCGETS
|
||||||
|
|
||||||
|
func isTerminal(fd int) bool {
|
||||||
|
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
|
@ -12,18 +12,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
nocolor = 0
|
red = 31
|
||||||
red = 31
|
yellow = 33
|
||||||
green = 32
|
blue = 36
|
||||||
yellow = 33
|
gray = 37
|
||||||
blue = 36
|
|
||||||
gray = 37
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var baseTimestamp time.Time
|
||||||
baseTimestamp time.Time
|
|
||||||
emptyFieldMap FieldMap
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
baseTimestamp = time.Now()
|
baseTimestamp = time.Now()
|
||||||
|
@ -77,6 +72,12 @@ type TextFormatter struct {
|
||||||
// FieldKeyMsg: "@message"}}
|
// FieldKeyMsg: "@message"}}
|
||||||
FieldMap FieldMap
|
FieldMap FieldMap
|
||||||
|
|
||||||
|
// CallerPrettyfier can be set by the user to modify the content
|
||||||
|
// of the function and file keys in the data when ReportCaller is
|
||||||
|
// activated. If any of the returned value is the empty string the
|
||||||
|
// corresponding key will be removed from fields.
|
||||||
|
CallerPrettyfier func(*runtime.Frame) (function string, file string)
|
||||||
|
|
||||||
terminalInitOnce sync.Once
|
terminalInitOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +119,8 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var funcVal, fileVal string
|
||||||
|
|
||||||
fixedKeys := make([]string, 0, 4+len(data))
|
fixedKeys := make([]string, 0, 4+len(data))
|
||||||
if !f.DisableTimestamp {
|
if !f.DisableTimestamp {
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
||||||
|
@ -130,8 +133,19 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
||||||
}
|
}
|
||||||
if entry.HasCaller() {
|
if entry.HasCaller() {
|
||||||
fixedKeys = append(fixedKeys,
|
if f.CallerPrettyfier != nil {
|
||||||
f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile))
|
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||||
|
} else {
|
||||||
|
funcVal = entry.Caller.Function
|
||||||
|
fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
|
}
|
||||||
|
|
||||||
|
if funcVal != "" {
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc))
|
||||||
|
}
|
||||||
|
if fileVal != "" {
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !f.DisableSorting {
|
if !f.DisableSorting {
|
||||||
|
@ -166,6 +180,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
if f.isColored() {
|
if f.isColored() {
|
||||||
f.printColored(b, entry, keys, data, timestampFormat)
|
f.printColored(b, entry, keys, data, timestampFormat)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
for _, key := range fixedKeys {
|
for _, key := range fixedKeys {
|
||||||
var value interface{}
|
var value interface{}
|
||||||
switch {
|
switch {
|
||||||
|
@ -178,9 +193,9 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
case key == f.FieldMap.resolve(FieldKeyLogrusError):
|
case key == f.FieldMap.resolve(FieldKeyLogrusError):
|
||||||
value = entry.err
|
value = entry.err
|
||||||
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
|
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
|
||||||
value = entry.Caller.Function
|
value = funcVal
|
||||||
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
|
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
|
||||||
value = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
value = fileVal
|
||||||
default:
|
default:
|
||||||
value = data[key]
|
value = data[key]
|
||||||
}
|
}
|
||||||
|
@ -215,10 +230,21 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
||||||
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
||||||
|
|
||||||
caller := ""
|
caller := ""
|
||||||
|
|
||||||
if entry.HasCaller() {
|
if entry.HasCaller() {
|
||||||
caller = fmt.Sprintf("%s:%d %s()",
|
funcVal := fmt.Sprintf("%s()", entry.Caller.Function)
|
||||||
entry.Caller.File, entry.Caller.Line, entry.Caller.Function)
|
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
|
|
||||||
|
if f.CallerPrettyfier != nil {
|
||||||
|
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fileVal == "" {
|
||||||
|
caller = funcVal
|
||||||
|
} else if funcVal == "" {
|
||||||
|
caller = fileVal
|
||||||
|
} else {
|
||||||
|
caller = fileVal + " " + funcVal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.DisableTimestamp {
|
if f.DisableTimestamp {
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
# This source code refers to The Go Authors for copyright purposes.
|
|
||||||
# The master list of authors is in the main Go distribution,
|
|
||||||
# visible at https://tip.golang.org/AUTHORS.
|
|
|
@ -1,3 +0,0 @@
|
||||||
# This source code was written by the Go contributors.
|
|
||||||
# The master list of contributors is in the main Go distribution,
|
|
||||||
# visible at https://tip.golang.org/CONTRIBUTORS.
|
|
|
@ -1,27 +0,0 @@
|
||||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,22 +0,0 @@
|
||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
|
@ -1,955 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package terminal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"sync"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EscapeCodes contains escape sequences that can be written to the terminal in
|
|
||||||
// order to achieve different styles of text.
|
|
||||||
type EscapeCodes struct {
|
|
||||||
// Foreground colors
|
|
||||||
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
|
|
||||||
|
|
||||||
// Reset all attributes
|
|
||||||
Reset []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
var vt100EscapeCodes = EscapeCodes{
|
|
||||||
Black: []byte{keyEscape, '[', '3', '0', 'm'},
|
|
||||||
Red: []byte{keyEscape, '[', '3', '1', 'm'},
|
|
||||||
Green: []byte{keyEscape, '[', '3', '2', 'm'},
|
|
||||||
Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
|
|
||||||
Blue: []byte{keyEscape, '[', '3', '4', 'm'},
|
|
||||||
Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
|
|
||||||
Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
|
|
||||||
White: []byte{keyEscape, '[', '3', '7', 'm'},
|
|
||||||
|
|
||||||
Reset: []byte{keyEscape, '[', '0', 'm'},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminal contains the state for running a VT100 terminal that is capable of
|
|
||||||
// reading lines of input.
|
|
||||||
type Terminal struct {
|
|
||||||
// AutoCompleteCallback, if non-null, is called for each keypress with
|
|
||||||
// the full input line and the current position of the cursor (in
|
|
||||||
// bytes, as an index into |line|). If it returns ok=false, the key
|
|
||||||
// press is processed normally. Otherwise it returns a replacement line
|
|
||||||
// and the new cursor position.
|
|
||||||
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
|
|
||||||
|
|
||||||
// Escape contains a pointer to the escape codes for this terminal.
|
|
||||||
// It's always a valid pointer, although the escape codes themselves
|
|
||||||
// may be empty if the terminal doesn't support them.
|
|
||||||
Escape *EscapeCodes
|
|
||||||
|
|
||||||
// lock protects the terminal and the state in this object from
|
|
||||||
// concurrent processing of a key press and a Write() call.
|
|
||||||
lock sync.Mutex
|
|
||||||
|
|
||||||
c io.ReadWriter
|
|
||||||
prompt []rune
|
|
||||||
|
|
||||||
// line is the current line being entered.
|
|
||||||
line []rune
|
|
||||||
// pos is the logical position of the cursor in line
|
|
||||||
pos int
|
|
||||||
// echo is true if local echo is enabled
|
|
||||||
echo bool
|
|
||||||
// pasteActive is true iff there is a bracketed paste operation in
|
|
||||||
// progress.
|
|
||||||
pasteActive bool
|
|
||||||
|
|
||||||
// cursorX contains the current X value of the cursor where the left
|
|
||||||
// edge is 0. cursorY contains the row number where the first row of
|
|
||||||
// the current line is 0.
|
|
||||||
cursorX, cursorY int
|
|
||||||
// maxLine is the greatest value of cursorY so far.
|
|
||||||
maxLine int
|
|
||||||
|
|
||||||
termWidth, termHeight int
|
|
||||||
|
|
||||||
// outBuf contains the terminal data to be sent.
|
|
||||||
outBuf []byte
|
|
||||||
// remainder contains the remainder of any partial key sequences after
|
|
||||||
// a read. It aliases into inBuf.
|
|
||||||
remainder []byte
|
|
||||||
inBuf [256]byte
|
|
||||||
|
|
||||||
// history contains previously entered commands so that they can be
|
|
||||||
// accessed with the up and down keys.
|
|
||||||
history stRingBuffer
|
|
||||||
// historyIndex stores the currently accessed history entry, where zero
|
|
||||||
// means the immediately previous entry.
|
|
||||||
historyIndex int
|
|
||||||
// When navigating up and down the history it's possible to return to
|
|
||||||
// the incomplete, initial line. That value is stored in
|
|
||||||
// historyPending.
|
|
||||||
historyPending string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
|
|
||||||
// a local terminal, that terminal must first have been put into raw mode.
|
|
||||||
// prompt is a string that is written at the start of each input line (i.e.
|
|
||||||
// "> ").
|
|
||||||
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
|
|
||||||
return &Terminal{
|
|
||||||
Escape: &vt100EscapeCodes,
|
|
||||||
c: c,
|
|
||||||
prompt: []rune(prompt),
|
|
||||||
termWidth: 80,
|
|
||||||
termHeight: 24,
|
|
||||||
echo: true,
|
|
||||||
historyIndex: -1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
keyCtrlD = 4
|
|
||||||
keyCtrlU = 21
|
|
||||||
keyEnter = '\r'
|
|
||||||
keyEscape = 27
|
|
||||||
keyBackspace = 127
|
|
||||||
keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
|
|
||||||
keyUp
|
|
||||||
keyDown
|
|
||||||
keyLeft
|
|
||||||
keyRight
|
|
||||||
keyAltLeft
|
|
||||||
keyAltRight
|
|
||||||
keyHome
|
|
||||||
keyEnd
|
|
||||||
keyDeleteWord
|
|
||||||
keyDeleteLine
|
|
||||||
keyClearScreen
|
|
||||||
keyPasteStart
|
|
||||||
keyPasteEnd
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
crlf = []byte{'\r', '\n'}
|
|
||||||
pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
|
|
||||||
pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
|
|
||||||
)
|
|
||||||
|
|
||||||
// bytesToKey tries to parse a key sequence from b. If successful, it returns
|
|
||||||
// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
|
|
||||||
func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
|
|
||||||
if len(b) == 0 {
|
|
||||||
return utf8.RuneError, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !pasteActive {
|
|
||||||
switch b[0] {
|
|
||||||
case 1: // ^A
|
|
||||||
return keyHome, b[1:]
|
|
||||||
case 5: // ^E
|
|
||||||
return keyEnd, b[1:]
|
|
||||||
case 8: // ^H
|
|
||||||
return keyBackspace, b[1:]
|
|
||||||
case 11: // ^K
|
|
||||||
return keyDeleteLine, b[1:]
|
|
||||||
case 12: // ^L
|
|
||||||
return keyClearScreen, b[1:]
|
|
||||||
case 23: // ^W
|
|
||||||
return keyDeleteWord, b[1:]
|
|
||||||
case 14: // ^N
|
|
||||||
return keyDown, b[1:]
|
|
||||||
case 16: // ^P
|
|
||||||
return keyUp, b[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if b[0] != keyEscape {
|
|
||||||
if !utf8.FullRune(b) {
|
|
||||||
return utf8.RuneError, b
|
|
||||||
}
|
|
||||||
r, l := utf8.DecodeRune(b)
|
|
||||||
return r, b[l:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
|
|
||||||
switch b[2] {
|
|
||||||
case 'A':
|
|
||||||
return keyUp, b[3:]
|
|
||||||
case 'B':
|
|
||||||
return keyDown, b[3:]
|
|
||||||
case 'C':
|
|
||||||
return keyRight, b[3:]
|
|
||||||
case 'D':
|
|
||||||
return keyLeft, b[3:]
|
|
||||||
case 'H':
|
|
||||||
return keyHome, b[3:]
|
|
||||||
case 'F':
|
|
||||||
return keyEnd, b[3:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
|
|
||||||
switch b[5] {
|
|
||||||
case 'C':
|
|
||||||
return keyAltRight, b[6:]
|
|
||||||
case 'D':
|
|
||||||
return keyAltLeft, b[6:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) {
|
|
||||||
return keyPasteStart, b[6:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) {
|
|
||||||
return keyPasteEnd, b[6:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we get here then we have a key that we don't recognise, or a
|
|
||||||
// partial sequence. It's not clear how one should find the end of a
|
|
||||||
// sequence without knowing them all, but it seems that [a-zA-Z~] only
|
|
||||||
// appears at the end of a sequence.
|
|
||||||
for i, c := range b[0:] {
|
|
||||||
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' {
|
|
||||||
return keyUnknown, b[i+1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return utf8.RuneError, b
|
|
||||||
}
|
|
||||||
|
|
||||||
// queue appends data to the end of t.outBuf
|
|
||||||
func (t *Terminal) queue(data []rune) {
|
|
||||||
t.outBuf = append(t.outBuf, []byte(string(data))...)
|
|
||||||
}
|
|
||||||
|
|
||||||
var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
|
|
||||||
var space = []rune{' '}
|
|
||||||
|
|
||||||
func isPrintable(key rune) bool {
|
|
||||||
isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
|
|
||||||
return key >= 32 && !isInSurrogateArea
|
|
||||||
}
|
|
||||||
|
|
||||||
// moveCursorToPos appends data to t.outBuf which will move the cursor to the
|
|
||||||
// given, logical position in the text.
|
|
||||||
func (t *Terminal) moveCursorToPos(pos int) {
|
|
||||||
if !t.echo {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
x := visualLength(t.prompt) + pos
|
|
||||||
y := x / t.termWidth
|
|
||||||
x = x % t.termWidth
|
|
||||||
|
|
||||||
up := 0
|
|
||||||
if y < t.cursorY {
|
|
||||||
up = t.cursorY - y
|
|
||||||
}
|
|
||||||
|
|
||||||
down := 0
|
|
||||||
if y > t.cursorY {
|
|
||||||
down = y - t.cursorY
|
|
||||||
}
|
|
||||||
|
|
||||||
left := 0
|
|
||||||
if x < t.cursorX {
|
|
||||||
left = t.cursorX - x
|
|
||||||
}
|
|
||||||
|
|
||||||
right := 0
|
|
||||||
if x > t.cursorX {
|
|
||||||
right = x - t.cursorX
|
|
||||||
}
|
|
||||||
|
|
||||||
t.cursorX = x
|
|
||||||
t.cursorY = y
|
|
||||||
t.move(up, down, left, right)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Terminal) move(up, down, left, right int) {
|
|
||||||
movement := make([]rune, 3*(up+down+left+right))
|
|
||||||
m := movement
|
|
||||||
for i := 0; i < up; i++ {
|
|
||||||
m[0] = keyEscape
|
|
||||||
m[1] = '['
|
|
||||||
m[2] = 'A'
|
|
||||||
m = m[3:]
|
|
||||||
}
|
|
||||||
for i := 0; i < down; i++ {
|
|
||||||
m[0] = keyEscape
|
|
||||||
m[1] = '['
|
|
||||||
m[2] = 'B'
|
|
||||||
m = m[3:]
|
|
||||||
}
|
|
||||||
for i := 0; i < left; i++ {
|
|
||||||
m[0] = keyEscape
|
|
||||||
m[1] = '['
|
|
||||||
m[2] = 'D'
|
|
||||||
m = m[3:]
|
|
||||||
}
|
|
||||||
for i := 0; i < right; i++ {
|
|
||||||
m[0] = keyEscape
|
|
||||||
m[1] = '['
|
|
||||||
m[2] = 'C'
|
|
||||||
m = m[3:]
|
|
||||||
}
|
|
||||||
|
|
||||||
t.queue(movement)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Terminal) clearLineToRight() {
|
|
||||||
op := []rune{keyEscape, '[', 'K'}
|
|
||||||
t.queue(op)
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxLineLength = 4096
|
|
||||||
|
|
||||||
func (t *Terminal) setLine(newLine []rune, newPos int) {
|
|
||||||
if t.echo {
|
|
||||||
t.moveCursorToPos(0)
|
|
||||||
t.writeLine(newLine)
|
|
||||||
for i := len(newLine); i < len(t.line); i++ {
|
|
||||||
t.writeLine(space)
|
|
||||||
}
|
|
||||||
t.moveCursorToPos(newPos)
|
|
||||||
}
|
|
||||||
t.line = newLine
|
|
||||||
t.pos = newPos
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Terminal) advanceCursor(places int) {
|
|
||||||
t.cursorX += places
|
|
||||||
t.cursorY += t.cursorX / t.termWidth
|
|
||||||
if t.cursorY > t.maxLine {
|
|
||||||
t.maxLine = t.cursorY
|
|
||||||
}
|
|
||||||
t.cursorX = t.cursorX % t.termWidth
|
|
||||||
|
|
||||||
if places > 0 && t.cursorX == 0 {
|
|
||||||
// Normally terminals will advance the current position
|
|
||||||
// when writing a character. But that doesn't happen
|
|
||||||
// for the last character in a line. However, when
|
|
||||||
// writing a character (except a new line) that causes
|
|
||||||
// a line wrap, the position will be advanced two
|
|
||||||
// places.
|
|
||||||
//
|
|
||||||
// So, if we are stopping at the end of a line, we
|
|
||||||
// need to write a newline so that our cursor can be
|
|
||||||
// advanced to the next line.
|
|
||||||
t.outBuf = append(t.outBuf, '\r', '\n')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Terminal) eraseNPreviousChars(n int) {
|
|
||||||
if n == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.pos < n {
|
|
||||||
n = t.pos
|
|
||||||
}
|
|
||||||
t.pos -= n
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
|
|
||||||
copy(t.line[t.pos:], t.line[n+t.pos:])
|
|
||||||
t.line = t.line[:len(t.line)-n]
|
|
||||||
if t.echo {
|
|
||||||
t.writeLine(t.line[t.pos:])
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
t.queue(space)
|
|
||||||
}
|
|
||||||
t.advanceCursor(n)
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// countToLeftWord returns then number of characters from the cursor to the
|
|
||||||
// start of the previous word.
|
|
||||||
func (t *Terminal) countToLeftWord() int {
|
|
||||||
if t.pos == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pos := t.pos - 1
|
|
||||||
for pos > 0 {
|
|
||||||
if t.line[pos] != ' ' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
pos--
|
|
||||||
}
|
|
||||||
for pos > 0 {
|
|
||||||
if t.line[pos] == ' ' {
|
|
||||||
pos++
|
|
||||||
break
|
|
||||||
}
|
|
||||||
pos--
|
|
||||||
}
|
|
||||||
|
|
||||||
return t.pos - pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// countToRightWord returns then number of characters from the cursor to the
|
|
||||||
// start of the next word.
|
|
||||||
func (t *Terminal) countToRightWord() int {
|
|
||||||
pos := t.pos
|
|
||||||
for pos < len(t.line) {
|
|
||||||
if t.line[pos] == ' ' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
pos++
|
|
||||||
}
|
|
||||||
for pos < len(t.line) {
|
|
||||||
if t.line[pos] != ' ' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
pos++
|
|
||||||
}
|
|
||||||
return pos - t.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// visualLength returns the number of visible glyphs in s.
|
|
||||||
func visualLength(runes []rune) int {
|
|
||||||
inEscapeSeq := false
|
|
||||||
length := 0
|
|
||||||
|
|
||||||
for _, r := range runes {
|
|
||||||
switch {
|
|
||||||
case inEscapeSeq:
|
|
||||||
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
|
|
||||||
inEscapeSeq = false
|
|
||||||
}
|
|
||||||
case r == '\x1b':
|
|
||||||
inEscapeSeq = true
|
|
||||||
default:
|
|
||||||
length++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return length
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleKey processes the given key and, optionally, returns a line of text
|
|
||||||
// that the user has entered.
|
|
||||||
func (t *Terminal) handleKey(key rune) (line string, ok bool) {
|
|
||||||
if t.pasteActive && key != keyEnter {
|
|
||||||
t.addKeyToLine(key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch key {
|
|
||||||
case keyBackspace:
|
|
||||||
if t.pos == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.eraseNPreviousChars(1)
|
|
||||||
case keyAltLeft:
|
|
||||||
// move left by a word.
|
|
||||||
t.pos -= t.countToLeftWord()
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
case keyAltRight:
|
|
||||||
// move right by a word.
|
|
||||||
t.pos += t.countToRightWord()
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
case keyLeft:
|
|
||||||
if t.pos == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.pos--
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
case keyRight:
|
|
||||||
if t.pos == len(t.line) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.pos++
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
case keyHome:
|
|
||||||
if t.pos == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.pos = 0
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
case keyEnd:
|
|
||||||
if t.pos == len(t.line) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.pos = len(t.line)
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
case keyUp:
|
|
||||||
entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
|
|
||||||
if !ok {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
if t.historyIndex == -1 {
|
|
||||||
t.historyPending = string(t.line)
|
|
||||||
}
|
|
||||||
t.historyIndex++
|
|
||||||
runes := []rune(entry)
|
|
||||||
t.setLine(runes, len(runes))
|
|
||||||
case keyDown:
|
|
||||||
switch t.historyIndex {
|
|
||||||
case -1:
|
|
||||||
return
|
|
||||||
case 0:
|
|
||||||
runes := []rune(t.historyPending)
|
|
||||||
t.setLine(runes, len(runes))
|
|
||||||
t.historyIndex--
|
|
||||||
default:
|
|
||||||
entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
|
|
||||||
if ok {
|
|
||||||
t.historyIndex--
|
|
||||||
runes := []rune(entry)
|
|
||||||
t.setLine(runes, len(runes))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case keyEnter:
|
|
||||||
t.moveCursorToPos(len(t.line))
|
|
||||||
t.queue([]rune("\r\n"))
|
|
||||||
line = string(t.line)
|
|
||||||
ok = true
|
|
||||||
t.line = t.line[:0]
|
|
||||||
t.pos = 0
|
|
||||||
t.cursorX = 0
|
|
||||||
t.cursorY = 0
|
|
||||||
t.maxLine = 0
|
|
||||||
case keyDeleteWord:
|
|
||||||
// Delete zero or more spaces and then one or more characters.
|
|
||||||
t.eraseNPreviousChars(t.countToLeftWord())
|
|
||||||
case keyDeleteLine:
|
|
||||||
// Delete everything from the current cursor position to the
|
|
||||||
// end of line.
|
|
||||||
for i := t.pos; i < len(t.line); i++ {
|
|
||||||
t.queue(space)
|
|
||||||
t.advanceCursor(1)
|
|
||||||
}
|
|
||||||
t.line = t.line[:t.pos]
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
case keyCtrlD:
|
|
||||||
// Erase the character under the current position.
|
|
||||||
// The EOF case when the line is empty is handled in
|
|
||||||
// readLine().
|
|
||||||
if t.pos < len(t.line) {
|
|
||||||
t.pos++
|
|
||||||
t.eraseNPreviousChars(1)
|
|
||||||
}
|
|
||||||
case keyCtrlU:
|
|
||||||
t.eraseNPreviousChars(t.pos)
|
|
||||||
case keyClearScreen:
|
|
||||||
// Erases the screen and moves the cursor to the home position.
|
|
||||||
t.queue([]rune("\x1b[2J\x1b[H"))
|
|
||||||
t.queue(t.prompt)
|
|
||||||
t.cursorX, t.cursorY = 0, 0
|
|
||||||
t.advanceCursor(visualLength(t.prompt))
|
|
||||||
t.setLine(t.line, t.pos)
|
|
||||||
default:
|
|
||||||
if t.AutoCompleteCallback != nil {
|
|
||||||
prefix := string(t.line[:t.pos])
|
|
||||||
suffix := string(t.line[t.pos:])
|
|
||||||
|
|
||||||
t.lock.Unlock()
|
|
||||||
newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
|
|
||||||
t.lock.Lock()
|
|
||||||
|
|
||||||
if completeOk {
|
|
||||||
t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !isPrintable(key) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(t.line) == maxLineLength {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.addKeyToLine(key)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// addKeyToLine inserts the given key at the current position in the current
|
|
||||||
// line.
|
|
||||||
func (t *Terminal) addKeyToLine(key rune) {
|
|
||||||
if len(t.line) == cap(t.line) {
|
|
||||||
newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
|
|
||||||
copy(newLine, t.line)
|
|
||||||
t.line = newLine
|
|
||||||
}
|
|
||||||
t.line = t.line[:len(t.line)+1]
|
|
||||||
copy(t.line[t.pos+1:], t.line[t.pos:])
|
|
||||||
t.line[t.pos] = key
|
|
||||||
if t.echo {
|
|
||||||
t.writeLine(t.line[t.pos:])
|
|
||||||
}
|
|
||||||
t.pos++
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Terminal) writeLine(line []rune) {
|
|
||||||
for len(line) != 0 {
|
|
||||||
remainingOnLine := t.termWidth - t.cursorX
|
|
||||||
todo := len(line)
|
|
||||||
if todo > remainingOnLine {
|
|
||||||
todo = remainingOnLine
|
|
||||||
}
|
|
||||||
t.queue(line[:todo])
|
|
||||||
t.advanceCursor(visualLength(line[:todo]))
|
|
||||||
line = line[todo:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n.
|
|
||||||
func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) {
|
|
||||||
for len(buf) > 0 {
|
|
||||||
i := bytes.IndexByte(buf, '\n')
|
|
||||||
todo := len(buf)
|
|
||||||
if i >= 0 {
|
|
||||||
todo = i
|
|
||||||
}
|
|
||||||
|
|
||||||
var nn int
|
|
||||||
nn, err = w.Write(buf[:todo])
|
|
||||||
n += nn
|
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
buf = buf[todo:]
|
|
||||||
|
|
||||||
if i >= 0 {
|
|
||||||
if _, err = w.Write(crlf); err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
n++
|
|
||||||
buf = buf[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Terminal) Write(buf []byte) (n int, err error) {
|
|
||||||
t.lock.Lock()
|
|
||||||
defer t.lock.Unlock()
|
|
||||||
|
|
||||||
if t.cursorX == 0 && t.cursorY == 0 {
|
|
||||||
// This is the easy case: there's nothing on the screen that we
|
|
||||||
// have to move out of the way.
|
|
||||||
return writeWithCRLF(t.c, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have a prompt and possibly user input on the screen. We
|
|
||||||
// have to clear it first.
|
|
||||||
t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
|
|
||||||
t.cursorX = 0
|
|
||||||
t.clearLineToRight()
|
|
||||||
|
|
||||||
for t.cursorY > 0 {
|
|
||||||
t.move(1 /* up */, 0, 0, 0)
|
|
||||||
t.cursorY--
|
|
||||||
t.clearLineToRight()
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = t.c.Write(t.outBuf); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.outBuf = t.outBuf[:0]
|
|
||||||
|
|
||||||
if n, err = writeWithCRLF(t.c, buf); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t.writeLine(t.prompt)
|
|
||||||
if t.echo {
|
|
||||||
t.writeLine(t.line)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
|
|
||||||
if _, err = t.c.Write(t.outBuf); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.outBuf = t.outBuf[:0]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadPassword temporarily changes the prompt and reads a password, without
|
|
||||||
// echo, from the terminal.
|
|
||||||
func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
|
|
||||||
t.lock.Lock()
|
|
||||||
defer t.lock.Unlock()
|
|
||||||
|
|
||||||
oldPrompt := t.prompt
|
|
||||||
t.prompt = []rune(prompt)
|
|
||||||
t.echo = false
|
|
||||||
|
|
||||||
line, err = t.readLine()
|
|
||||||
|
|
||||||
t.prompt = oldPrompt
|
|
||||||
t.echo = true
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadLine returns a line of input from the terminal.
|
|
||||||
func (t *Terminal) ReadLine() (line string, err error) {
|
|
||||||
t.lock.Lock()
|
|
||||||
defer t.lock.Unlock()
|
|
||||||
|
|
||||||
return t.readLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Terminal) readLine() (line string, err error) {
|
|
||||||
// t.lock must be held at this point
|
|
||||||
|
|
||||||
if t.cursorX == 0 && t.cursorY == 0 {
|
|
||||||
t.writeLine(t.prompt)
|
|
||||||
t.c.Write(t.outBuf)
|
|
||||||
t.outBuf = t.outBuf[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
lineIsPasted := t.pasteActive
|
|
||||||
|
|
||||||
for {
|
|
||||||
rest := t.remainder
|
|
||||||
lineOk := false
|
|
||||||
for !lineOk {
|
|
||||||
var key rune
|
|
||||||
key, rest = bytesToKey(rest, t.pasteActive)
|
|
||||||
if key == utf8.RuneError {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if !t.pasteActive {
|
|
||||||
if key == keyCtrlD {
|
|
||||||
if len(t.line) == 0 {
|
|
||||||
return "", io.EOF
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if key == keyPasteStart {
|
|
||||||
t.pasteActive = true
|
|
||||||
if len(t.line) == 0 {
|
|
||||||
lineIsPasted = true
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else if key == keyPasteEnd {
|
|
||||||
t.pasteActive = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !t.pasteActive {
|
|
||||||
lineIsPasted = false
|
|
||||||
}
|
|
||||||
line, lineOk = t.handleKey(key)
|
|
||||||
}
|
|
||||||
if len(rest) > 0 {
|
|
||||||
n := copy(t.inBuf[:], rest)
|
|
||||||
t.remainder = t.inBuf[:n]
|
|
||||||
} else {
|
|
||||||
t.remainder = nil
|
|
||||||
}
|
|
||||||
t.c.Write(t.outBuf)
|
|
||||||
t.outBuf = t.outBuf[:0]
|
|
||||||
if lineOk {
|
|
||||||
if t.echo {
|
|
||||||
t.historyIndex = -1
|
|
||||||
t.history.Add(line)
|
|
||||||
}
|
|
||||||
if lineIsPasted {
|
|
||||||
err = ErrPasteIndicator
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// t.remainder is a slice at the beginning of t.inBuf
|
|
||||||
// containing a partial key sequence
|
|
||||||
readBuf := t.inBuf[len(t.remainder):]
|
|
||||||
var n int
|
|
||||||
|
|
||||||
t.lock.Unlock()
|
|
||||||
n, err = t.c.Read(readBuf)
|
|
||||||
t.lock.Lock()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t.remainder = t.inBuf[:n+len(t.remainder)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPrompt sets the prompt to be used when reading subsequent lines.
|
|
||||||
func (t *Terminal) SetPrompt(prompt string) {
|
|
||||||
t.lock.Lock()
|
|
||||||
defer t.lock.Unlock()
|
|
||||||
|
|
||||||
t.prompt = []rune(prompt)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
|
|
||||||
// Move cursor to column zero at the start of the line.
|
|
||||||
t.move(t.cursorY, 0, t.cursorX, 0)
|
|
||||||
t.cursorX, t.cursorY = 0, 0
|
|
||||||
t.clearLineToRight()
|
|
||||||
for t.cursorY < numPrevLines {
|
|
||||||
// Move down a line
|
|
||||||
t.move(0, 1, 0, 0)
|
|
||||||
t.cursorY++
|
|
||||||
t.clearLineToRight()
|
|
||||||
}
|
|
||||||
// Move back to beginning.
|
|
||||||
t.move(t.cursorY, 0, 0, 0)
|
|
||||||
t.cursorX, t.cursorY = 0, 0
|
|
||||||
|
|
||||||
t.queue(t.prompt)
|
|
||||||
t.advanceCursor(visualLength(t.prompt))
|
|
||||||
t.writeLine(t.line)
|
|
||||||
t.moveCursorToPos(t.pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Terminal) SetSize(width, height int) error {
|
|
||||||
t.lock.Lock()
|
|
||||||
defer t.lock.Unlock()
|
|
||||||
|
|
||||||
if width == 0 {
|
|
||||||
width = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
oldWidth := t.termWidth
|
|
||||||
t.termWidth, t.termHeight = width, height
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case width == oldWidth:
|
|
||||||
// If the width didn't change then nothing else needs to be
|
|
||||||
// done.
|
|
||||||
return nil
|
|
||||||
case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
|
|
||||||
// If there is nothing on current line and no prompt printed,
|
|
||||||
// just do nothing
|
|
||||||
return nil
|
|
||||||
case width < oldWidth:
|
|
||||||
// Some terminals (e.g. xterm) will truncate lines that were
|
|
||||||
// too long when shinking. Others, (e.g. gnome-terminal) will
|
|
||||||
// attempt to wrap them. For the former, repainting t.maxLine
|
|
||||||
// works great, but that behaviour goes badly wrong in the case
|
|
||||||
// of the latter because they have doubled every full line.
|
|
||||||
|
|
||||||
// We assume that we are working on a terminal that wraps lines
|
|
||||||
// and adjust the cursor position based on every previous line
|
|
||||||
// wrapping and turning into two. This causes the prompt on
|
|
||||||
// xterms to move upwards, which isn't great, but it avoids a
|
|
||||||
// huge mess with gnome-terminal.
|
|
||||||
if t.cursorX >= t.termWidth {
|
|
||||||
t.cursorX = t.termWidth - 1
|
|
||||||
}
|
|
||||||
t.cursorY *= 2
|
|
||||||
t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
|
|
||||||
case width > oldWidth:
|
|
||||||
// If the terminal expands then our position calculations will
|
|
||||||
// be wrong in the future because we think the cursor is
|
|
||||||
// |t.pos| chars into the string, but there will be a gap at
|
|
||||||
// the end of any wrapped line.
|
|
||||||
//
|
|
||||||
// But the position will actually be correct until we move, so
|
|
||||||
// we can move back to the beginning and repaint everything.
|
|
||||||
t.clearAndRepaintLinePlusNPrevious(t.maxLine)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := t.c.Write(t.outBuf)
|
|
||||||
t.outBuf = t.outBuf[:0]
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
type pasteIndicatorError struct{}
|
|
||||||
|
|
||||||
func (pasteIndicatorError) Error() string {
|
|
||||||
return "terminal: ErrPasteIndicator not correctly handled"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrPasteIndicator may be returned from ReadLine as the error, in addition
|
|
||||||
// to valid line data. It indicates that bracketed paste mode is enabled and
|
|
||||||
// that the returned line consists only of pasted data. Programs may wish to
|
|
||||||
// interpret pasted data more literally than typed data.
|
|
||||||
var ErrPasteIndicator = pasteIndicatorError{}
|
|
||||||
|
|
||||||
// SetBracketedPasteMode requests that the terminal bracket paste operations
|
|
||||||
// with markers. Not all terminals support this but, if it is supported, then
|
|
||||||
// enabling this mode will stop any autocomplete callback from running due to
|
|
||||||
// pastes. Additionally, any lines that are completely pasted will be returned
|
|
||||||
// from ReadLine with the error set to ErrPasteIndicator.
|
|
||||||
func (t *Terminal) SetBracketedPasteMode(on bool) {
|
|
||||||
if on {
|
|
||||||
io.WriteString(t.c, "\x1b[?2004h")
|
|
||||||
} else {
|
|
||||||
io.WriteString(t.c, "\x1b[?2004l")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// stRingBuffer is a ring buffer of strings.
|
|
||||||
type stRingBuffer struct {
|
|
||||||
// entries contains max elements.
|
|
||||||
entries []string
|
|
||||||
max int
|
|
||||||
// head contains the index of the element most recently added to the ring.
|
|
||||||
head int
|
|
||||||
// size contains the number of elements in the ring.
|
|
||||||
size int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stRingBuffer) Add(a string) {
|
|
||||||
if s.entries == nil {
|
|
||||||
const defaultNumEntries = 100
|
|
||||||
s.entries = make([]string, defaultNumEntries)
|
|
||||||
s.max = defaultNumEntries
|
|
||||||
}
|
|
||||||
|
|
||||||
s.head = (s.head + 1) % s.max
|
|
||||||
s.entries[s.head] = a
|
|
||||||
if s.size < s.max {
|
|
||||||
s.size++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NthPreviousEntry returns the value passed to the nth previous call to Add.
|
|
||||||
// If n is zero then the immediately prior value is returned, if one, then the
|
|
||||||
// next most recent, and so on. If such an element doesn't exist then ok is
|
|
||||||
// false.
|
|
||||||
func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
|
|
||||||
if n >= s.size {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
index := s.head - n
|
|
||||||
if index < 0 {
|
|
||||||
index += s.max
|
|
||||||
}
|
|
||||||
return s.entries[index], true
|
|
||||||
}
|
|
||||||
|
|
||||||
// readPasswordLine reads from reader until it finds \n or io.EOF.
|
|
||||||
// The slice returned does not include the \n.
|
|
||||||
// readPasswordLine also ignores any \r it finds.
|
|
||||||
func readPasswordLine(reader io.Reader) ([]byte, error) {
|
|
||||||
var buf [1]byte
|
|
||||||
var ret []byte
|
|
||||||
|
|
||||||
for {
|
|
||||||
n, err := reader.Read(buf[:])
|
|
||||||
if n > 0 {
|
|
||||||
switch buf[0] {
|
|
||||||
case '\n':
|
|
||||||
return ret, nil
|
|
||||||
case '\r':
|
|
||||||
// remove \r from passwords on Windows
|
|
||||||
default:
|
|
||||||
ret = append(ret, buf[0])
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF && len(ret) > 0 {
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
return ret, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd
|
|
||||||
|
|
||||||
// Package terminal provides support functions for dealing with terminals, as
|
|
||||||
// commonly found on UNIX systems.
|
|
||||||
//
|
|
||||||
// Putting a terminal into raw mode is the most common requirement:
|
|
||||||
//
|
|
||||||
// oldState, err := terminal.MakeRaw(0)
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
// defer terminal.Restore(0, oldState)
|
|
||||||
package terminal // import "golang.org/x/crypto/ssh/terminal"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// State contains the state of a terminal.
|
|
||||||
type State struct {
|
|
||||||
termios unix.Termios
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
|
||||||
func IsTerminal(fd int) bool {
|
|
||||||
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
|
||||||
// mode and returns the previous state of the terminal so that it can be
|
|
||||||
// restored.
|
|
||||||
func MakeRaw(fd int) (*State, error) {
|
|
||||||
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
oldState := State{termios: *termios}
|
|
||||||
|
|
||||||
// This attempts to replicate the behaviour documented for cfmakeraw in
|
|
||||||
// the termios(3) manpage.
|
|
||||||
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
|
|
||||||
termios.Oflag &^= unix.OPOST
|
|
||||||
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
|
|
||||||
termios.Cflag &^= unix.CSIZE | unix.PARENB
|
|
||||||
termios.Cflag |= unix.CS8
|
|
||||||
termios.Cc[unix.VMIN] = 1
|
|
||||||
termios.Cc[unix.VTIME] = 0
|
|
||||||
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &oldState, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetState returns the current state of a terminal which may be useful to
|
|
||||||
// restore the terminal after a signal.
|
|
||||||
func GetState(fd int) (*State, error) {
|
|
||||||
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &State{termios: *termios}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore restores the terminal connected to the given file descriptor to a
|
|
||||||
// previous state.
|
|
||||||
func Restore(fd int, state *State) error {
|
|
||||||
return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSize returns the dimensions of the given terminal.
|
|
||||||
func GetSize(fd int) (width, height int, err error) {
|
|
||||||
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
|
|
||||||
if err != nil {
|
|
||||||
return -1, -1, err
|
|
||||||
}
|
|
||||||
return int(ws.Col), int(ws.Row), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// passwordReader is an io.Reader that reads from a specific file descriptor.
|
|
||||||
type passwordReader int
|
|
||||||
|
|
||||||
func (r passwordReader) Read(buf []byte) (int, error) {
|
|
||||||
return unix.Read(int(r), buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadPassword reads a line of input from a terminal without local echo. This
|
|
||||||
// is commonly used for inputting passwords and other sensitive data. The slice
|
|
||||||
// returned does not include the \n.
|
|
||||||
func ReadPassword(fd int) ([]byte, error) {
|
|
||||||
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
newState := *termios
|
|
||||||
newState.Lflag &^= unix.ECHO
|
|
||||||
newState.Lflag |= unix.ICANON | unix.ISIG
|
|
||||||
newState.Iflag |= unix.ICRNL
|
|
||||||
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
|
|
||||||
|
|
||||||
return readPasswordLine(passwordReader(fd))
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build aix
|
|
||||||
|
|
||||||
package terminal
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
const ioctlReadTermios = unix.TCGETS
|
|
||||||
const ioctlWriteTermios = unix.TCSETS
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build darwin dragonfly freebsd netbsd openbsd
|
|
||||||
|
|
||||||
package terminal
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
const ioctlReadTermios = unix.TIOCGETA
|
|
||||||
const ioctlWriteTermios = unix.TIOCSETA
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package terminal
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
const ioctlReadTermios = unix.TCGETS
|
|
||||||
const ioctlWriteTermios = unix.TCSETS
|
|
|
@ -1,58 +0,0 @@
|
||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package terminal provides support functions for dealing with terminals, as
|
|
||||||
// commonly found on UNIX systems.
|
|
||||||
//
|
|
||||||
// Putting a terminal into raw mode is the most common requirement:
|
|
||||||
//
|
|
||||||
// oldState, err := terminal.MakeRaw(0)
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
// defer terminal.Restore(0, oldState)
|
|
||||||
package terminal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
type State struct{}
|
|
||||||
|
|
||||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
|
||||||
func IsTerminal(fd int) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
|
||||||
// mode and returns the previous state of the terminal so that it can be
|
|
||||||
// restored.
|
|
||||||
func MakeRaw(fd int) (*State, error) {
|
|
||||||
return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetState returns the current state of a terminal which may be useful to
|
|
||||||
// restore the terminal after a signal.
|
|
||||||
func GetState(fd int) (*State, error) {
|
|
||||||
return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore restores the terminal connected to the given file descriptor to a
|
|
||||||
// previous state.
|
|
||||||
func Restore(fd int, state *State) error {
|
|
||||||
return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSize returns the dimensions of the given terminal.
|
|
||||||
func GetSize(fd int) (width, height int, err error) {
|
|
||||||
return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadPassword reads a line of input from a terminal without local echo. This
|
|
||||||
// is commonly used for inputting passwords and other sensitive data. The slice
|
|
||||||
// returned does not include the \n.
|
|
||||||
func ReadPassword(fd int) ([]byte, error) {
|
|
||||||
return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build solaris
|
|
||||||
|
|
||||||
package terminal // import "golang.org/x/crypto/ssh/terminal"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
"io"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// State contains the state of a terminal.
|
|
||||||
type State struct {
|
|
||||||
termios unix.Termios
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
|
||||||
func IsTerminal(fd int) bool {
|
|
||||||
_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadPassword reads a line of input from a terminal without local echo. This
|
|
||||||
// is commonly used for inputting passwords and other sensitive data. The slice
|
|
||||||
// returned does not include the \n.
|
|
||||||
func ReadPassword(fd int) ([]byte, error) {
|
|
||||||
// see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
|
|
||||||
val, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
oldState := *val
|
|
||||||
|
|
||||||
newState := oldState
|
|
||||||
newState.Lflag &^= syscall.ECHO
|
|
||||||
newState.Lflag |= syscall.ICANON | syscall.ISIG
|
|
||||||
newState.Iflag |= syscall.ICRNL
|
|
||||||
err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState)
|
|
||||||
|
|
||||||
var buf [16]byte
|
|
||||||
var ret []byte
|
|
||||||
for {
|
|
||||||
n, err := syscall.Read(fd, buf[:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
if len(ret) == 0 {
|
|
||||||
return nil, io.EOF
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if buf[n-1] == '\n' {
|
|
||||||
n--
|
|
||||||
}
|
|
||||||
ret = append(ret, buf[:n]...)
|
|
||||||
if n < len(buf) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRaw puts the terminal connected to the given file descriptor into raw
|
|
||||||
// mode and returns the previous state of the terminal so that it can be
|
|
||||||
// restored.
|
|
||||||
// see http://cr.illumos.org/~webrev/andy_js/1060/
|
|
||||||
func MakeRaw(fd int) (*State, error) {
|
|
||||||
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
oldState := State{termios: *termios}
|
|
||||||
|
|
||||||
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
|
|
||||||
termios.Oflag &^= unix.OPOST
|
|
||||||
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
|
|
||||||
termios.Cflag &^= unix.CSIZE | unix.PARENB
|
|
||||||
termios.Cflag |= unix.CS8
|
|
||||||
termios.Cc[unix.VMIN] = 1
|
|
||||||
termios.Cc[unix.VTIME] = 0
|
|
||||||
|
|
||||||
if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &oldState, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore restores the terminal connected to the given file descriptor to a
|
|
||||||
// previous state.
|
|
||||||
func Restore(fd int, oldState *State) error {
|
|
||||||
return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetState returns the current state of a terminal which may be useful to
|
|
||||||
// restore the terminal after a signal.
|
|
||||||
func GetState(fd int) (*State, error) {
|
|
||||||
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &State{termios: *termios}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSize returns the dimensions of the given terminal.
|
|
||||||
func GetSize(fd int) (width, height int, err error) {
|
|
||||||
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, err
|
|
||||||
}
|
|
||||||
return int(ws.Col), int(ws.Row), nil
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
// Package terminal provides support functions for dealing with terminals, as
|
|
||||||
// commonly found on UNIX systems.
|
|
||||||
//
|
|
||||||
// Putting a terminal into raw mode is the most common requirement:
|
|
||||||
//
|
|
||||||
// oldState, err := terminal.MakeRaw(0)
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
// defer terminal.Restore(0, oldState)
|
|
||||||
package terminal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
type State struct {
|
|
||||||
mode uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
|
||||||
func IsTerminal(fd int) bool {
|
|
||||||
var st uint32
|
|
||||||
err := windows.GetConsoleMode(windows.Handle(fd), &st)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
|
||||||
// mode and returns the previous state of the terminal so that it can be
|
|
||||||
// restored.
|
|
||||||
func MakeRaw(fd int) (*State, error) {
|
|
||||||
var st uint32
|
|
||||||
if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT)
|
|
||||||
if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &State{st}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetState returns the current state of a terminal which may be useful to
|
|
||||||
// restore the terminal after a signal.
|
|
||||||
func GetState(fd int) (*State, error) {
|
|
||||||
var st uint32
|
|
||||||
if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &State{st}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore restores the terminal connected to the given file descriptor to a
|
|
||||||
// previous state.
|
|
||||||
func Restore(fd int, state *State) error {
|
|
||||||
return windows.SetConsoleMode(windows.Handle(fd), state.mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSize returns the dimensions of the given terminal.
|
|
||||||
func GetSize(fd int) (width, height int, err error) {
|
|
||||||
var info windows.ConsoleScreenBufferInfo
|
|
||||||
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
|
|
||||||
return 0, 0, err
|
|
||||||
}
|
|
||||||
return int(info.Size.X), int(info.Size.Y), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadPassword reads a line of input from a terminal without local echo. This
|
|
||||||
// is commonly used for inputting passwords and other sensitive data. The slice
|
|
||||||
// returned does not include the \n.
|
|
||||||
func ReadPassword(fd int) ([]byte, error) {
|
|
||||||
var st uint32
|
|
||||||
if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
old := st
|
|
||||||
|
|
||||||
st &^= (windows.ENABLE_ECHO_INPUT)
|
|
||||||
st |= (windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT)
|
|
||||||
if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer windows.SetConsoleMode(windows.Handle(fd), old)
|
|
||||||
|
|
||||||
var h windows.Handle
|
|
||||||
p, _ := windows.GetCurrentProcess()
|
|
||||||
if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
f := os.NewFile(uintptr(h), "stdin")
|
|
||||||
defer f.Close()
|
|
||||||
return readPasswordLine(f)
|
|
||||||
}
|
|
|
@ -2,8 +2,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build go1.9
|
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build go1.9
|
|
||||||
// +build linux
|
// +build linux
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build go1.9
|
|
||||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
|
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
|
@ -2,17 +2,14 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build go1.9
|
|
||||||
// +build !linux
|
// +build !linux
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
|
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
|
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,14 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build go1.9
|
|
||||||
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
|
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func (c *Conn) recvMsg(m *Message, flags int) error {
|
func (c *Conn) recvMsg(m *Message, flags int) error {
|
||||||
return errors.New("not implemented")
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) sendMsg(m *Message, flags int) error {
|
func (c *Conn) sendMsg(m *Message, flags int) error {
|
||||||
return errors.New("not implemented")
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !go1.9
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func (c *Conn) recvMsg(m *Message, flags int) error {
|
|
||||||
return errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) sendMsg(m *Message, flags int) error {
|
|
||||||
return errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
|
|
||||||
return 0, errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
|
|
||||||
return 0, errors.New("not implemented")
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !go1.9
|
|
||||||
|
|
||||||
package socket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Conn represents a raw connection.
|
|
||||||
type Conn struct {
|
|
||||||
c net.Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConn returns a new raw connection.
|
|
||||||
func NewConn(c net.Conn) (*Conn, error) {
|
|
||||||
return &Conn{c: c}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Option) get(c *Conn, b []byte) (int, error) {
|
|
||||||
s, err := socketOf(c.c)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
n, err := getsockopt(s, o.Level, o.Name, b)
|
|
||||||
return n, os.NewSyscallError("getsockopt", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Option) set(c *Conn, b []byte) error {
|
|
||||||
s, err := socketOf(c.c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return os.NewSyscallError("setsockopt", setsockopt(s, o.Level, o.Name, b))
|
|
||||||
}
|
|
||||||
|
|
||||||
func socketOf(c net.Conn) (uintptr, error) {
|
|
||||||
switch c.(type) {
|
|
||||||
case *net.TCPConn, *net.UDPConn, *net.IPConn:
|
|
||||||
v := reflect.ValueOf(c)
|
|
||||||
switch e := v.Elem(); e.Kind() {
|
|
||||||
case reflect.Struct:
|
|
||||||
fd := e.FieldByName("conn").FieldByName("fd")
|
|
||||||
switch e := fd.Elem(); e.Kind() {
|
|
||||||
case reflect.Struct:
|
|
||||||
sysfd := e.FieldByName("sysfd")
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
return uintptr(sysfd.Uint()), nil
|
|
||||||
}
|
|
||||||
return uintptr(sysfd.Int()), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0, errors.New("invalid type")
|
|
||||||
}
|
|
|
@ -9,9 +9,12 @@ package socket // import "golang.org/x/net/internal/socket"
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errNotImplemented = errors.New("not implemented on " + runtime.GOOS + "/" + runtime.GOARCH)
|
||||||
|
|
||||||
// An Option represents a sticky socket option.
|
// An Option represents a sticky socket option.
|
||||||
type Option struct {
|
type Option struct {
|
||||||
Level int // level
|
Level int // level
|
||||||
|
|
|
@ -29,5 +29,5 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func roundup(l int) int {
|
func roundup(l int) int {
|
||||||
return (l + kernelAlign - 1) & ^(kernelAlign - 1)
|
return (l + kernelAlign - 1) &^ (kernelAlign - 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,10 @@
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func probeProtocolStack() int {
|
func probeProtocolStack() int {
|
||||||
if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
|
if (runtime.GOOS == "netbsd" || runtime.GOOS == "openbsd") && runtime.GOARCH == "arm" {
|
||||||
return 8
|
return 8
|
||||||
}
|
}
|
||||||
var p uintptr
|
var p uintptr
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build go1.9
|
|
||||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
|
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
|
||||||
|
|
||||||
package socket
|
package socket
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -63,9 +62,9 @@ func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -36,29 +35,29 @@ func marshalInetAddr(ip net.IP, port int, zone string) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseInetAddr(b []byte, network string) (net.Addr, error) {
|
func parseInetAddr(b []byte, network string) (net.Addr, error) {
|
||||||
return nil, errors.New("not implemented")
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
|
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func setsockopt(s uintptr, level, name int, b []byte) error {
|
func setsockopt(s uintptr, level, name int, b []byte) error {
|
||||||
return errors.New("not implemented")
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
func recvmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
@ -54,17 +53,17 @@ func setsockopt(s uintptr, level, name int, b []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
func recvmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
func sendmsg(s uintptr, h *msghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
|
||||||
return 0, errors.New("not implemented")
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build go1.9
|
|
||||||
|
|
||||||
package ipv4
|
package ipv4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -91,6 +89,9 @@ func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
|
||||||
n = 0
|
n = 0
|
||||||
err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
|
err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
|
||||||
}
|
}
|
||||||
|
if compatFreeBSD32 && ms[0].NN > 0 {
|
||||||
|
adjustFreeBSD32(&ms[0])
|
||||||
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,6 +155,9 @@ func (c *packetHandler) ReadBatch(ms []Message, flags int) (int, error) {
|
||||||
n = 0
|
n = 0
|
||||||
err = &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
|
err = &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
|
||||||
}
|
}
|
||||||
|
if compatFreeBSD32 && ms[0].NN > 0 {
|
||||||
|
adjustFreeBSD32(&ms[0])
|
||||||
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,5 @@ package ipv4
|
||||||
import "golang.org/x/net/internal/socket"
|
import "golang.org/x/net/internal/socket"
|
||||||
|
|
||||||
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
|
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,9 @@
|
||||||
|
|
||||||
package ipv4
|
package ipv4
|
||||||
|
|
||||||
import (
|
import "golang.org/x/net/internal/socket"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"golang.org/x/net/internal/socket"
|
|
||||||
)
|
|
||||||
|
|
||||||
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
|
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
|
||||||
// TODO(mikio): implement this
|
// TODO(mikio): implement this
|
||||||
return syscall.EWINDOWS
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ func (c *dgramOpt) MulticastTTL() (int, error) {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoMulticastTTL]
|
so, ok := sockOpts[ssoMulticastTTL]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, errOpNoSupport
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
return so.GetInt(c.Conn)
|
return so.GetInt(c.Conn)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ func (c *dgramOpt) SetMulticastTTL(ttl int) error {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoMulticastTTL]
|
so, ok := sockOpts[ssoMulticastTTL]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
return so.SetInt(c.Conn, ttl)
|
return so.SetInt(c.Conn, ttl)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoMulticastInterface]
|
so, ok := sockOpts[ssoMulticastInterface]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errOpNoSupport
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
return so.getMulticastInterface(c.Conn)
|
return so.getMulticastInterface(c.Conn)
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoMulticastInterface]
|
so, ok := sockOpts[ssoMulticastInterface]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
return so.setMulticastInterface(c.Conn, ifi)
|
return so.setMulticastInterface(c.Conn, ifi)
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ func (c *dgramOpt) MulticastLoopback() (bool, error) {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoMulticastLoopback]
|
so, ok := sockOpts[ssoMulticastLoopback]
|
||||||
if !ok {
|
if !ok {
|
||||||
return false, errOpNoSupport
|
return false, errNotImplemented
|
||||||
}
|
}
|
||||||
on, err := so.GetInt(c.Conn)
|
on, err := so.GetInt(c.Conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -87,7 +87,7 @@ func (c *dgramOpt) SetMulticastLoopback(on bool) error {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoMulticastLoopback]
|
so, ok := sockOpts[ssoMulticastLoopback]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
return so.SetInt(c.Conn, boolint(on))
|
return so.SetInt(c.Conn, boolint(on))
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoJoinGroup]
|
so, ok := sockOpts[ssoJoinGroup]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
grp := netAddrToIP4(group)
|
grp := netAddrToIP4(group)
|
||||||
if grp == nil {
|
if grp == nil {
|
||||||
|
@ -125,7 +125,7 @@ func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoLeaveGroup]
|
so, ok := sockOpts[ssoLeaveGroup]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
grp := netAddrToIP4(group)
|
grp := netAddrToIP4(group)
|
||||||
if grp == nil {
|
if grp == nil {
|
||||||
|
@ -146,7 +146,7 @@ func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoJoinSourceGroup]
|
so, ok := sockOpts[ssoJoinSourceGroup]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
grp := netAddrToIP4(group)
|
grp := netAddrToIP4(group)
|
||||||
if grp == nil {
|
if grp == nil {
|
||||||
|
@ -167,7 +167,7 @@ func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source ne
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoLeaveSourceGroup]
|
so, ok := sockOpts[ssoLeaveSourceGroup]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
grp := netAddrToIP4(group)
|
grp := netAddrToIP4(group)
|
||||||
if grp == nil {
|
if grp == nil {
|
||||||
|
@ -189,7 +189,7 @@ func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoBlockSourceGroup]
|
so, ok := sockOpts[ssoBlockSourceGroup]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
grp := netAddrToIP4(group)
|
grp := netAddrToIP4(group)
|
||||||
if grp == nil {
|
if grp == nil {
|
||||||
|
@ -210,7 +210,7 @@ func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoUnblockSourceGroup]
|
so, ok := sockOpts[ssoUnblockSourceGroup]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
grp := netAddrToIP4(group)
|
grp := netAddrToIP4(group)
|
||||||
if grp == nil {
|
if grp == nil {
|
||||||
|
@ -231,7 +231,7 @@ func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoICMPFilter]
|
so, ok := sockOpts[ssoICMPFilter]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errOpNoSupport
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
return so.getICMPFilter(c.Conn)
|
return so.getICMPFilter(c.Conn)
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoICMPFilter]
|
so, ok := sockOpts[ssoICMPFilter]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
return so.setICMPFilter(c.Conn, f)
|
return so.setICMPFilter(c.Conn, f)
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,7 @@ func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoAttachFilter]
|
so, ok := sockOpts[ssoAttachFilter]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
return so.setBPF(c.Conn, filter)
|
return so.setBPF(c.Conn, filter)
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,7 +209,7 @@
|
||||||
// LeaveSourceSpecificGroup for the operation known as "include" mode,
|
// LeaveSourceSpecificGroup for the operation known as "include" mode,
|
||||||
//
|
//
|
||||||
// ssmgroup := net.UDPAddr{IP: net.IPv4(232, 7, 8, 9)}
|
// ssmgroup := net.UDPAddr{IP: net.IPv4(232, 7, 8, 9)}
|
||||||
// ssmsource := net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)})
|
// ssmsource := net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)}
|
||||||
// if err := p.JoinSourceSpecificGroup(en0, &ssmgroup, &ssmsource); err != nil {
|
// if err := p.JoinSourceSpecificGroup(en0, &ssmgroup, &ssmsource); err != nil {
|
||||||
// // error handling
|
// // error handling
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -177,7 +177,7 @@ func NewRawConn(c net.PacketConn) (*RawConn, error) {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoHeaderPrepend]
|
so, ok := sockOpts[ssoHeaderPrepend]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errOpNoSupport
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
if err := so.SetInt(r.dgramOpt.Conn, boolint(true)); err != nil {
|
if err := so.SetInt(r.dgramOpt.Conn, boolint(true)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -11,7 +11,7 @@ func (c *genericOpt) TOS() (int, error) {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoTOS]
|
so, ok := sockOpts[ssoTOS]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, errOpNoSupport
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
return so.GetInt(c.Conn)
|
return so.GetInt(c.Conn)
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ func (c *genericOpt) SetTOS(tos int) error {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoTOS]
|
so, ok := sockOpts[ssoTOS]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
return so.SetInt(c.Conn, tos)
|
return so.SetInt(c.Conn, tos)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func (c *genericOpt) TTL() (int, error) {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoTTL]
|
so, ok := sockOpts[ssoTTL]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, errOpNoSupport
|
return 0, errNotImplemented
|
||||||
}
|
}
|
||||||
return so.GetInt(c.Conn)
|
return so.GetInt(c.Conn)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ func (c *genericOpt) SetTTL(ttl int) error {
|
||||||
}
|
}
|
||||||
so, ok := sockOpts[ssoTTL]
|
so, ok := sockOpts[ssoTTL]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
return so.SetInt(c.Conn, ttl)
|
return so.SetInt(c.Conn, ttl)
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ func (h *Header) String() string {
|
||||||
// This may differ from the wire format, depending on the system.
|
// This may differ from the wire format, depending on the system.
|
||||||
func (h *Header) Marshal() ([]byte, error) {
|
func (h *Header) Marshal() ([]byte, error) {
|
||||||
if h == nil {
|
if h == nil {
|
||||||
return nil, errInvalidConn
|
return nil, errNilHeader
|
||||||
}
|
}
|
||||||
if h.Len < HeaderLen {
|
if h.Len < HeaderLen {
|
||||||
return nil, errHeaderTooShort
|
return nil, errHeaderTooShort
|
||||||
|
@ -107,12 +107,15 @@ func (h *Header) Marshal() ([]byte, error) {
|
||||||
// local system.
|
// local system.
|
||||||
// This may differ from the wire format, depending on the system.
|
// This may differ from the wire format, depending on the system.
|
||||||
func (h *Header) Parse(b []byte) error {
|
func (h *Header) Parse(b []byte) error {
|
||||||
if h == nil || len(b) < HeaderLen {
|
if h == nil || b == nil {
|
||||||
|
return errNilHeader
|
||||||
|
}
|
||||||
|
if len(b) < HeaderLen {
|
||||||
return errHeaderTooShort
|
return errHeaderTooShort
|
||||||
}
|
}
|
||||||
hdrlen := int(b[0]&0x0f) << 2
|
hdrlen := int(b[0]&0x0f) << 2
|
||||||
if hdrlen > len(b) {
|
if len(b) < hdrlen {
|
||||||
return errBufferTooShort
|
return errExtHeaderTooShort
|
||||||
}
|
}
|
||||||
h.Version = int(b[0] >> 4)
|
h.Version = int(b[0] >> 4)
|
||||||
h.Len = hdrlen
|
h.Len = hdrlen
|
||||||
|
|
|
@ -7,23 +7,38 @@ package ipv4
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"golang.org/x/net/internal/socket"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errInvalidConn = errors.New("invalid connection")
|
errInvalidConn = errors.New("invalid connection")
|
||||||
errMissingAddress = errors.New("missing address")
|
errMissingAddress = errors.New("missing address")
|
||||||
errMissingHeader = errors.New("missing header")
|
errMissingHeader = errors.New("missing header")
|
||||||
|
errNilHeader = errors.New("nil header")
|
||||||
errHeaderTooShort = errors.New("header too short")
|
errHeaderTooShort = errors.New("header too short")
|
||||||
errBufferTooShort = errors.New("buffer too short")
|
errExtHeaderTooShort = errors.New("extension header too short")
|
||||||
errInvalidConnType = errors.New("invalid conn type")
|
errInvalidConnType = errors.New("invalid conn type")
|
||||||
errOpNoSupport = errors.New("operation not supported")
|
|
||||||
errNoSuchInterface = errors.New("no such interface")
|
errNoSuchInterface = errors.New("no such interface")
|
||||||
errNoSuchMulticastInterface = errors.New("no such multicast interface")
|
errNoSuchMulticastInterface = errors.New("no such multicast interface")
|
||||||
|
errNotImplemented = errors.New("not implemented on " + runtime.GOOS + "/" + runtime.GOARCH)
|
||||||
|
|
||||||
// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
|
// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
|
||||||
freebsdVersion uint32
|
freebsdVersion uint32
|
||||||
|
compatFreeBSD32 bool // 386 emulation on amd64
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// See golang.org/issue/30899.
|
||||||
|
func adjustFreeBSD32(m *socket.Message) {
|
||||||
|
if freebsdVersion >= 1103000 {
|
||||||
|
l := (m.NN + 4 - 1) &^ (4 - 1)
|
||||||
|
if m.NN < l && l <= len(m.OOB) {
|
||||||
|
m.NN = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func boolint(b bool) int {
|
func boolint(b bool) int {
|
||||||
if b {
|
if b {
|
||||||
return 1
|
return 1
|
||||||
|
|
|
@ -29,7 +29,35 @@ func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMess
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return nil, nil, nil, errInvalidConn
|
return nil, nil, nil, errInvalidConn
|
||||||
}
|
}
|
||||||
return c.readFrom(b)
|
c.rawOpt.RLock()
|
||||||
|
m := socket.Message{
|
||||||
|
Buffers: [][]byte{b},
|
||||||
|
OOB: NewControlMessage(c.rawOpt.cflags),
|
||||||
|
}
|
||||||
|
c.rawOpt.RUnlock()
|
||||||
|
if err := c.RecvMsg(&m, 0); err != nil {
|
||||||
|
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
|
||||||
|
}
|
||||||
|
var hs []byte
|
||||||
|
if hs, p, err = slicePacket(b[:m.N]); err != nil {
|
||||||
|
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
|
||||||
|
}
|
||||||
|
if h, err = ParseHeader(hs); err != nil {
|
||||||
|
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
|
||||||
|
}
|
||||||
|
if m.NN > 0 {
|
||||||
|
if compatFreeBSD32 {
|
||||||
|
adjustFreeBSD32(&m)
|
||||||
|
}
|
||||||
|
cm = new(ControlMessage)
|
||||||
|
if err := cm.Parse(m.OOB[:m.NN]); err != nil {
|
||||||
|
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if src, ok := m.Addr.(*net.IPAddr); ok && cm != nil {
|
||||||
|
cm.Src = src.IP
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func slicePacket(b []byte) (h, p []byte, err error) {
|
func slicePacket(b []byte) (h, p []byte, err error) {
|
||||||
|
@ -64,5 +92,26 @@ func (c *packetHandler) WriteTo(h *Header, p []byte, cm *ControlMessage) error {
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return errInvalidConn
|
return errInvalidConn
|
||||||
}
|
}
|
||||||
return c.writeTo(h, p, cm)
|
m := socket.Message{
|
||||||
|
OOB: cm.Marshal(),
|
||||||
|
}
|
||||||
|
wh, err := h.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.Buffers = [][]byte{wh, p}
|
||||||
|
dst := new(net.IPAddr)
|
||||||
|
if cm != nil {
|
||||||
|
if ip := cm.Dst.To4(); ip != nil {
|
||||||
|
dst.IP = ip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dst.IP == nil {
|
||||||
|
dst.IP = h.Dst
|
||||||
|
}
|
||||||
|
m.Addr = dst
|
||||||
|
if err := c.SendMsg(&m, 0); err != nil {
|
||||||
|
return &net.OpError{Op: "write", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Addr: opAddr(dst), Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !go1.9
|
|
||||||
|
|
||||||
package ipv4
|
|
||||||
|
|
||||||
import "net"
|
|
||||||
|
|
||||||
func (c *packetHandler) readFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) {
|
|
||||||
c.rawOpt.RLock()
|
|
||||||
oob := NewControlMessage(c.rawOpt.cflags)
|
|
||||||
c.rawOpt.RUnlock()
|
|
||||||
n, nn, _, src, err := c.ReadMsgIP(b, oob)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
var hs []byte
|
|
||||||
if hs, p, err = slicePacket(b[:n]); err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
if h, err = ParseHeader(hs); err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
if nn > 0 {
|
|
||||||
cm = new(ControlMessage)
|
|
||||||
if err := cm.Parse(oob[:nn]); err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if src != nil && cm != nil {
|
|
||||||
cm.Src = src.IP
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *packetHandler) writeTo(h *Header, p []byte, cm *ControlMessage) error {
|
|
||||||
oob := cm.Marshal()
|
|
||||||
wh, err := h.Marshal()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dst := new(net.IPAddr)
|
|
||||||
if cm != nil {
|
|
||||||
if ip := cm.Dst.To4(); ip != nil {
|
|
||||||
dst.IP = ip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if dst.IP == nil {
|
|
||||||
dst.IP = h.Dst
|
|
||||||
}
|
|
||||||
wh = append(wh, p...)
|
|
||||||
_, _, err = c.WriteMsgIP(wh, oob, dst)
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build go1.9
|
|
||||||
|
|
||||||
package ipv4
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"golang.org/x/net/internal/socket"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *packetHandler) readFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) {
|
|
||||||
c.rawOpt.RLock()
|
|
||||||
m := socket.Message{
|
|
||||||
Buffers: [][]byte{b},
|
|
||||||
OOB: NewControlMessage(c.rawOpt.cflags),
|
|
||||||
}
|
|
||||||
c.rawOpt.RUnlock()
|
|
||||||
if err := c.RecvMsg(&m, 0); err != nil {
|
|
||||||
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
|
|
||||||
}
|
|
||||||
var hs []byte
|
|
||||||
if hs, p, err = slicePacket(b[:m.N]); err != nil {
|
|
||||||
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
|
|
||||||
}
|
|
||||||
if h, err = ParseHeader(hs); err != nil {
|
|
||||||
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
|
|
||||||
}
|
|
||||||
if m.NN > 0 {
|
|
||||||
cm = new(ControlMessage)
|
|
||||||
if err := cm.Parse(m.OOB[:m.NN]); err != nil {
|
|
||||||
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if src, ok := m.Addr.(*net.IPAddr); ok && cm != nil {
|
|
||||||
cm.Src = src.IP
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *packetHandler) writeTo(h *Header, p []byte, cm *ControlMessage) error {
|
|
||||||
m := socket.Message{
|
|
||||||
OOB: cm.Marshal(),
|
|
||||||
}
|
|
||||||
wh, err := h.Marshal()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.Buffers = [][]byte{wh, p}
|
|
||||||
dst := new(net.IPAddr)
|
|
||||||
if cm != nil {
|
|
||||||
if ip := cm.Dst.To4(); ip != nil {
|
|
||||||
dst.IP = ip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if dst.IP == nil {
|
|
||||||
dst.IP = h.Dst
|
|
||||||
}
|
|
||||||
m.Addr = dst
|
|
||||||
if err := c.SendMsg(&m, 0); err != nil {
|
|
||||||
return &net.OpError{Op: "write", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Addr: opAddr(dst), Err: err}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -6,7 +6,11 @@
|
||||||
|
|
||||||
package ipv4
|
package ipv4
|
||||||
|
|
||||||
import "net"
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"golang.org/x/net/internal/socket"
|
||||||
|
)
|
||||||
|
|
||||||
// ReadFrom reads a payload of the received IPv4 datagram, from the
|
// ReadFrom reads a payload of the received IPv4 datagram, from the
|
||||||
// endpoint c, copying the payload into b. It returns the number of
|
// endpoint c, copying the payload into b. It returns the number of
|
||||||
|
@ -16,7 +20,45 @@ func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, nil, nil, errInvalidConn
|
return 0, nil, nil, errInvalidConn
|
||||||
}
|
}
|
||||||
return c.readFrom(b)
|
c.rawOpt.RLock()
|
||||||
|
m := socket.Message{
|
||||||
|
OOB: NewControlMessage(c.rawOpt.cflags),
|
||||||
|
}
|
||||||
|
c.rawOpt.RUnlock()
|
||||||
|
switch c.PacketConn.(type) {
|
||||||
|
case *net.UDPConn:
|
||||||
|
m.Buffers = [][]byte{b}
|
||||||
|
if err := c.RecvMsg(&m, 0); err != nil {
|
||||||
|
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
|
||||||
|
}
|
||||||
|
case *net.IPConn:
|
||||||
|
h := make([]byte, HeaderLen)
|
||||||
|
m.Buffers = [][]byte{h, b}
|
||||||
|
if err := c.RecvMsg(&m, 0); err != nil {
|
||||||
|
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
|
||||||
|
}
|
||||||
|
hdrlen := int(h[0]&0x0f) << 2
|
||||||
|
if hdrlen > len(h) {
|
||||||
|
d := hdrlen - len(h)
|
||||||
|
copy(b, b[d:])
|
||||||
|
m.N -= d
|
||||||
|
} else {
|
||||||
|
m.N -= hdrlen
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: errInvalidConnType}
|
||||||
|
}
|
||||||
|
if m.NN > 0 {
|
||||||
|
if compatFreeBSD32 {
|
||||||
|
adjustFreeBSD32(&m)
|
||||||
|
}
|
||||||
|
cm = new(ControlMessage)
|
||||||
|
if err := cm.Parse(m.OOB[:m.NN]); err != nil {
|
||||||
|
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
|
||||||
|
}
|
||||||
|
cm.Src = netAddrToIP4(m.Addr)
|
||||||
|
}
|
||||||
|
return m.N, cm, m.Addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo writes a payload of the IPv4 datagram, to the destination
|
// WriteTo writes a payload of the IPv4 datagram, to the destination
|
||||||
|
@ -29,5 +71,14 @@ func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n
|
||||||
if !c.ok() {
|
if !c.ok() {
|
||||||
return 0, errInvalidConn
|
return 0, errInvalidConn
|
||||||
}
|
}
|
||||||
return c.writeTo(b, cm, dst)
|
m := socket.Message{
|
||||||
|
Buffers: [][]byte{b},
|
||||||
|
OOB: cm.Marshal(),
|
||||||
|
Addr: dst,
|
||||||
|
}
|
||||||
|
err = c.SendMsg(&m, 0)
|
||||||
|
if err != nil {
|
||||||
|
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Addr: opAddr(dst), Err: err}
|
||||||
|
}
|
||||||
|
return m.N, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !go1.9
|
|
||||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
|
||||||
|
|
||||||
package ipv4
|
|
||||||
|
|
||||||
import "net"
|
|
||||||
|
|
||||||
func (c *payloadHandler) readFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
|
|
||||||
c.rawOpt.RLock()
|
|
||||||
oob := NewControlMessage(c.rawOpt.cflags)
|
|
||||||
c.rawOpt.RUnlock()
|
|
||||||
var nn int
|
|
||||||
switch c := c.PacketConn.(type) {
|
|
||||||
case *net.UDPConn:
|
|
||||||
if n, nn, _, src, err = c.ReadMsgUDP(b, oob); err != nil {
|
|
||||||
return 0, nil, nil, err
|
|
||||||
}
|
|
||||||
case *net.IPConn:
|
|
||||||
nb := make([]byte, maxHeaderLen+len(b))
|
|
||||||
if n, nn, _, src, err = c.ReadMsgIP(nb, oob); err != nil {
|
|
||||||
return 0, nil, nil, err
|
|
||||||
}
|
|
||||||
hdrlen := int(nb[0]&0x0f) << 2
|
|
||||||
copy(b, nb[hdrlen:])
|
|
||||||
n -= hdrlen
|
|
||||||
default:
|
|
||||||
return 0, nil, nil, &net.OpError{Op: "read", Net: c.LocalAddr().Network(), Source: c.LocalAddr(), Err: errInvalidConnType}
|
|
||||||
}
|
|
||||||
if nn > 0 {
|
|
||||||
cm = new(ControlMessage)
|
|
||||||
if err = cm.Parse(oob[:nn]); err != nil {
|
|
||||||
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cm != nil {
|
|
||||||
cm.Src = netAddrToIP4(src)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *payloadHandler) writeTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
|
|
||||||
oob := cm.Marshal()
|
|
||||||
if dst == nil {
|
|
||||||
return 0, &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: errMissingAddress}
|
|
||||||
}
|
|
||||||
switch c := c.PacketConn.(type) {
|
|
||||||
case *net.UDPConn:
|
|
||||||
n, _, err = c.WriteMsgUDP(b, oob, dst.(*net.UDPAddr))
|
|
||||||
case *net.IPConn:
|
|
||||||
n, _, err = c.WriteMsgIP(b, oob, dst.(*net.IPAddr))
|
|
||||||
default:
|
|
||||||
return 0, &net.OpError{Op: "write", Net: c.LocalAddr().Network(), Source: c.LocalAddr(), Addr: opAddr(dst), Err: errInvalidConnType}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build go1.9
|
|
||||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
|
||||||
|
|
||||||
package ipv4
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"golang.org/x/net/internal/socket"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *payloadHandler) readFrom(b []byte) (int, *ControlMessage, net.Addr, error) {
|
|
||||||
c.rawOpt.RLock()
|
|
||||||
m := socket.Message{
|
|
||||||
OOB: NewControlMessage(c.rawOpt.cflags),
|
|
||||||
}
|
|
||||||
c.rawOpt.RUnlock()
|
|
||||||
switch c.PacketConn.(type) {
|
|
||||||
case *net.UDPConn:
|
|
||||||
m.Buffers = [][]byte{b}
|
|
||||||
if err := c.RecvMsg(&m, 0); err != nil {
|
|
||||||
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
|
|
||||||
}
|
|
||||||
case *net.IPConn:
|
|
||||||
h := make([]byte, HeaderLen)
|
|
||||||
m.Buffers = [][]byte{h, b}
|
|
||||||
if err := c.RecvMsg(&m, 0); err != nil {
|
|
||||||
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
|
|
||||||
}
|
|
||||||
hdrlen := int(h[0]&0x0f) << 2
|
|
||||||
if hdrlen > len(h) {
|
|
||||||
d := hdrlen - len(h)
|
|
||||||
copy(b, b[d:])
|
|
||||||
m.N -= d
|
|
||||||
} else {
|
|
||||||
m.N -= hdrlen
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: errInvalidConnType}
|
|
||||||
}
|
|
||||||
var cm *ControlMessage
|
|
||||||
if m.NN > 0 {
|
|
||||||
cm = new(ControlMessage)
|
|
||||||
if err := cm.Parse(m.OOB[:m.NN]); err != nil {
|
|
||||||
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
|
|
||||||
}
|
|
||||||
cm.Src = netAddrToIP4(m.Addr)
|
|
||||||
}
|
|
||||||
return m.N, cm, m.Addr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *payloadHandler) writeTo(b []byte, cm *ControlMessage, dst net.Addr) (int, error) {
|
|
||||||
m := socket.Message{
|
|
||||||
Buffers: [][]byte{b},
|
|
||||||
OOB: cm.Marshal(),
|
|
||||||
Addr: dst,
|
|
||||||
}
|
|
||||||
err := c.SendMsg(&m, 0)
|
|
||||||
if err != nil {
|
|
||||||
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Addr: opAddr(dst), Err: err}
|
|
||||||
}
|
|
||||||
return m.N, err
|
|
||||||
}
|
|
|
@ -39,7 +39,7 @@ func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if n != sizeofICMPFilter {
|
if n != sizeofICMPFilter {
|
||||||
return nil, errOpNoSupport
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
return (*ICMPFilter)(unsafe.Pointer(&b[0])), nil
|
return (*ICMPFilter)(unsafe.Pointer(&b[0])), nil
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) erro
|
||||||
case ssoTypeGroupReq:
|
case ssoTypeGroupReq:
|
||||||
return so.setGroupReq(c, ifi, grp)
|
return so.setGroupReq(c, ifi, grp)
|
||||||
default:
|
default:
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,29 +14,29 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
|
func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
|
||||||
return nil, errOpNoSupport
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
|
func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
|
func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
|
||||||
return nil, errOpNoSupport
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
|
func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
|
func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
|
func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
|
func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
|
func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *sockOpt) getMulticastIf(c *socket.Conn) (*net.Interface, error) {
|
func (so *sockOpt) getMulticastIf(c *socket.Conn) (*net.Interface, error) {
|
||||||
return nil, errOpNoSupport
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *sockOpt) setMulticastIf(c *socket.Conn, ifi *net.Interface) error {
|
func (so *sockOpt) setMulticastIf(c *socket.Conn, ifi *net.Interface) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (so *sockOpt) getIPMreqn(c *socket.Conn) (*net.Interface, error) {
|
func (so *sockOpt) getIPMreqn(c *socket.Conn) (*net.Interface, error) {
|
||||||
return nil, errOpNoSupport
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *sockOpt) setIPMreqn(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
|
func (so *sockOpt) setIPMreqn(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,5 +12,5 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (so *sockOpt) setAttachFilter(c *socket.Conn, f []bpf.RawInstruction) error {
|
func (so *sockOpt) setAttachFilter(c *socket.Conn, f []bpf.RawInstruction) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ func init() {
|
||||||
archs, _ := syscall.Sysctl("kern.supported_archs")
|
archs, _ := syscall.Sysctl("kern.supported_archs")
|
||||||
for _, s := range strings.Fields(archs) {
|
for _, s := range strings.Fields(archs) {
|
||||||
if s == "amd64" {
|
if s == "amd64" {
|
||||||
freebsd32o64 = true
|
compatFreeBSD32 = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,6 @@ import (
|
||||||
"golang.org/x/net/internal/socket"
|
"golang.org/x/net/internal/socket"
|
||||||
)
|
)
|
||||||
|
|
||||||
var freebsd32o64 bool
|
|
||||||
|
|
||||||
func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
|
func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
|
||||||
var gr groupReq
|
var gr groupReq
|
||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
|
@ -22,7 +20,7 @@ func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) e
|
||||||
}
|
}
|
||||||
gr.setGroup(grp)
|
gr.setGroup(grp)
|
||||||
var b []byte
|
var b []byte
|
||||||
if freebsd32o64 {
|
if compatFreeBSD32 {
|
||||||
var d [sizeofGroupReq + 4]byte
|
var d [sizeofGroupReq + 4]byte
|
||||||
s := (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))
|
s := (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))
|
||||||
copy(d[:4], s[:4])
|
copy(d[:4], s[:4])
|
||||||
|
@ -41,7 +39,7 @@ func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, sr
|
||||||
}
|
}
|
||||||
gsr.setSourceGroup(grp, src)
|
gsr.setSourceGroup(grp, src)
|
||||||
var b []byte
|
var b []byte
|
||||||
if freebsd32o64 {
|
if compatFreeBSD32 {
|
||||||
var d [sizeofGroupSourceReq + 4]byte
|
var d [sizeofGroupSourceReq + 4]byte
|
||||||
s := (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))
|
s := (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))
|
||||||
copy(d[:4], s[:4])
|
copy(d[:4], s[:4])
|
||||||
|
|
|
@ -13,9 +13,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
|
func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
|
func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
|
||||||
return errOpNoSupport
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ To build the files for your current OS and architecture, make sure GOOS and
|
||||||
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
|
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
|
||||||
your specific system. Running `mkall.sh -n` shows the commands that will be run.
|
your specific system. Running `mkall.sh -n` shows the commands that will be run.
|
||||||
|
|
||||||
Requirements: bash, perl, go
|
Requirements: bash, go
|
||||||
|
|
||||||
### New Build System (currently for `GOOS == "linux"`)
|
### New Build System (currently for `GOOS == "linux"`)
|
||||||
|
|
||||||
|
@ -52,14 +52,14 @@ system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
|
||||||
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
|
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
|
||||||
system. Running `mkall.sh -n` shows the commands that will be run.
|
system. Running `mkall.sh -n` shows the commands that will be run.
|
||||||
|
|
||||||
Requirements: bash, perl, go, docker
|
Requirements: bash, go, docker
|
||||||
|
|
||||||
## Component files
|
## Component files
|
||||||
|
|
||||||
This section describes the various files used in the code generation process.
|
This section describes the various files used in the code generation process.
|
||||||
It also contains instructions on how to modify these files to add a new
|
It also contains instructions on how to modify these files to add a new
|
||||||
architecture/OS or to add additional syscalls, types, or constants. Note that
|
architecture/OS or to add additional syscalls, types, or constants. Note that
|
||||||
if you are using the new build system, the scripts cannot be called normally.
|
if you are using the new build system, the scripts/programs cannot be called normally.
|
||||||
They must be called from within the docker container.
|
They must be called from within the docker container.
|
||||||
|
|
||||||
### asm files
|
### asm files
|
||||||
|
@ -81,8 +81,8 @@ each GOOS/GOARCH pair.
|
||||||
|
|
||||||
### mksysnum
|
### mksysnum
|
||||||
|
|
||||||
Mksysnum is a script located at `${GOOS}/mksysnum.pl` (or `mksysnum_${GOOS}.pl`
|
Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go`
|
||||||
for the old system). This script takes in a list of header files containing the
|
for the old system). This program takes in a list of header files containing the
|
||||||
syscall number declarations and parses them to produce the corresponding list of
|
syscall number declarations and parses them to produce the corresponding list of
|
||||||
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
|
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
|
||||||
constants.
|
constants.
|
||||||
|
@ -92,14 +92,14 @@ new installation of the target OS (or updating the source checkouts for the
|
||||||
new build system). However, depending on the OS, you make need to update the
|
new build system). However, depending on the OS, you make need to update the
|
||||||
parsing in mksysnum.
|
parsing in mksysnum.
|
||||||
|
|
||||||
### mksyscall.pl
|
### mksyscall.go
|
||||||
|
|
||||||
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
|
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
|
||||||
hand-written Go files which implement system calls (for unix, the specific OS,
|
hand-written Go files which implement system calls (for unix, the specific OS,
|
||||||
or the specific OS/Architecture pair respectively) that need special handling
|
or the specific OS/Architecture pair respectively) that need special handling
|
||||||
and list `//sys` comments giving prototypes for ones that can be generated.
|
and list `//sys` comments giving prototypes for ones that can be generated.
|
||||||
|
|
||||||
The mksyscall.pl script takes the `//sys` and `//sysnb` comments and converts
|
The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts
|
||||||
them into syscalls. This requires the name of the prototype in the comment to
|
them into syscalls. This requires the name of the prototype in the comment to
|
||||||
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
|
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
|
||||||
prototype can be exported (capitalized) or not.
|
prototype can be exported (capitalized) or not.
|
||||||
|
@ -160,7 +160,7 @@ signal numbers, and constants. Generated by `mkerrors.sh` (see above).
|
||||||
### `zsyscall_${GOOS}_${GOARCH}.go`
|
### `zsyscall_${GOOS}_${GOARCH}.go`
|
||||||
|
|
||||||
A file containing all the generated syscalls for a specific GOOS and GOARCH.
|
A file containing all the generated syscalls for a specific GOOS and GOARCH.
|
||||||
Generated by `mksyscall.pl` (see above).
|
Generated by `mksyscall.go` (see above).
|
||||||
|
|
||||||
### `zsysnum_${GOOS}_${GOARCH}.go`
|
### `zsysnum_${GOOS}_${GOARCH}.go`
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,7 @@ openbsd_arm)
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||||
;;
|
;;
|
||||||
solaris_amd64)
|
solaris_amd64)
|
||||||
mksyscall="./mksyscall_solaris.pl"
|
mksyscall="go run mksyscall_solaris.go"
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mksysnum=
|
mksysnum=
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
|
@ -207,8 +207,6 @@ esac
|
||||||
esac
|
esac
|
||||||
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
|
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
|
||||||
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
|
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
|
||||||
if [ -n "$mktypes" ]; then
|
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
|
||||||
echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go";
|
|
||||||
if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi
|
if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi
|
||||||
fi
|
|
||||||
) | $run
|
) | $run
|
||||||
|
|
|
@ -192,6 +192,7 @@ struct ltchars {
|
||||||
#include <linux/if_packet.h>
|
#include <linux/if_packet.h>
|
||||||
#include <linux/if_addr.h>
|
#include <linux/if_addr.h>
|
||||||
#include <linux/falloc.h>
|
#include <linux/falloc.h>
|
||||||
|
#include <linux/fanotify.h>
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/kexec.h>
|
#include <linux/kexec.h>
|
||||||
|
@ -501,6 +502,7 @@ ccflags="$@"
|
||||||
$2 !~ "WMESGLEN" &&
|
$2 !~ "WMESGLEN" &&
|
||||||
$2 ~ /^W[A-Z0-9]+$/ ||
|
$2 ~ /^W[A-Z0-9]+$/ ||
|
||||||
$2 ~/^PPPIOC/ ||
|
$2 ~/^PPPIOC/ ||
|
||||||
|
$2 ~ /^FAN_|FANOTIFY_/ ||
|
||||||
$2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)}
|
$2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)}
|
||||||
$2 ~ /^__WCOREFLAG$/ {next}
|
$2 ~ /^__WCOREFLAG$/ {next}
|
||||||
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
|
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
|
||||||
|
|
|
@ -228,7 +228,7 @@ func main() {
|
||||||
} else {
|
} else {
|
||||||
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name))
|
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name))
|
||||||
}
|
}
|
||||||
} else if p.Type == "int64" && endianness != "" {
|
} else if (p.Type == "int64" || p.Type == "uint64") && endianness != "" {
|
||||||
if len(args)%2 == 1 && *arm {
|
if len(args)%2 == 1 && *arm {
|
||||||
// arm abi specifies 64-bit argument uses
|
// arm abi specifies 64-bit argument uses
|
||||||
// (even, odd) pair
|
// (even, odd) pair
|
||||||
|
|
|
@ -0,0 +1,335 @@
|
||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
/*
|
||||||
|
This program reads a file containing function prototypes
|
||||||
|
(like syscall_solaris.go) and generates system call bodies.
|
||||||
|
The prototypes are marked by lines beginning with "//sys"
|
||||||
|
and read like func declarations if //sys is replaced by func, but:
|
||||||
|
* The parameter lists must give a name for each argument.
|
||||||
|
This includes return parameters.
|
||||||
|
* The parameter lists must give a type for each argument:
|
||||||
|
the (x, y, z int) shorthand is not allowed.
|
||||||
|
* If the return parameter is an error number, it must be named err.
|
||||||
|
* If go func name needs to be different than its libc name,
|
||||||
|
* or the function is not in libc, name could be specified
|
||||||
|
* at the end, after "=" sign, like
|
||||||
|
//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
b32 = flag.Bool("b32", false, "32bit big-endian")
|
||||||
|
l32 = flag.Bool("l32", false, "32bit little-endian")
|
||||||
|
tags = flag.String("tags", "", "build tags")
|
||||||
|
)
|
||||||
|
|
||||||
|
// cmdLine returns this programs's commandline arguments
|
||||||
|
func cmdLine() string {
|
||||||
|
return "go run mksyscall_solaris.go " + strings.Join(os.Args[1:], " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildTags returns build tags
|
||||||
|
func buildTags() string {
|
||||||
|
return *tags
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param is function parameter
|
||||||
|
type Param struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
// usage prints the program usage
|
||||||
|
func usage() {
|
||||||
|
fmt.Fprintf(os.Stderr, "usage: go run mksyscall_solaris.go [-b32 | -l32] [-tags x,y] [file ...]\n")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseParamList parses parameter list and returns a slice of parameters
|
||||||
|
func parseParamList(list string) []string {
|
||||||
|
list = strings.TrimSpace(list)
|
||||||
|
if list == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
return regexp.MustCompile(`\s*,\s*`).Split(list, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseParam splits a parameter into name and type
|
||||||
|
func parseParam(p string) Param {
|
||||||
|
ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p)
|
||||||
|
if ps == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return Param{ps[1], ps[2]}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Usage = usage
|
||||||
|
flag.Parse()
|
||||||
|
if len(flag.Args()) <= 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "no files to parse provided\n")
|
||||||
|
usage()
|
||||||
|
}
|
||||||
|
|
||||||
|
endianness := ""
|
||||||
|
if *b32 {
|
||||||
|
endianness = "big-endian"
|
||||||
|
} else if *l32 {
|
||||||
|
endianness = "little-endian"
|
||||||
|
}
|
||||||
|
|
||||||
|
pack := ""
|
||||||
|
text := ""
|
||||||
|
dynimports := ""
|
||||||
|
linknames := ""
|
||||||
|
var vars []string
|
||||||
|
for _, path := range flag.Args() {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
s := bufio.NewScanner(file)
|
||||||
|
for s.Scan() {
|
||||||
|
t := s.Text()
|
||||||
|
t = strings.TrimSpace(t)
|
||||||
|
t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `)
|
||||||
|
if p := regexp.MustCompile(`^package (\S+)$`).FindStringSubmatch(t); p != nil && pack == "" {
|
||||||
|
pack = p[1]
|
||||||
|
}
|
||||||
|
nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t)
|
||||||
|
if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line must be of the form
|
||||||
|
// func Open(path string, mode int, perm int) (fd int, err error)
|
||||||
|
// Split into name, in params, out params.
|
||||||
|
f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$`).FindStringSubmatch(t)
|
||||||
|
if f == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
funct, inps, outps, modname, sysname := f[2], f[3], f[4], f[5], f[6]
|
||||||
|
|
||||||
|
// Split argument lists on comma.
|
||||||
|
in := parseParamList(inps)
|
||||||
|
out := parseParamList(outps)
|
||||||
|
|
||||||
|
inps = strings.Join(in, ", ")
|
||||||
|
outps = strings.Join(out, ", ")
|
||||||
|
|
||||||
|
// Try in vain to keep people from editing this file.
|
||||||
|
// The theory is that they jump into the middle of the file
|
||||||
|
// without reading the header.
|
||||||
|
text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"
|
||||||
|
|
||||||
|
// So file name.
|
||||||
|
if modname == "" {
|
||||||
|
modname = "libc"
|
||||||
|
}
|
||||||
|
|
||||||
|
// System call name.
|
||||||
|
if sysname == "" {
|
||||||
|
sysname = funct
|
||||||
|
}
|
||||||
|
|
||||||
|
// System call pointer variable name.
|
||||||
|
sysvarname := fmt.Sprintf("proc%s", sysname)
|
||||||
|
|
||||||
|
strconvfunc := "BytePtrFromString"
|
||||||
|
strconvtype := "*byte"
|
||||||
|
|
||||||
|
sysname = strings.ToLower(sysname) // All libc functions are lowercase.
|
||||||
|
|
||||||
|
// Runtime import of function to allow cross-platform builds.
|
||||||
|
dynimports += fmt.Sprintf("//go:cgo_import_dynamic libc_%s %s \"%s.so\"\n", sysname, sysname, modname)
|
||||||
|
// Link symbol to proc address variable.
|
||||||
|
linknames += fmt.Sprintf("//go:linkname %s libc_%s\n", sysvarname, sysname)
|
||||||
|
// Library proc address variable.
|
||||||
|
vars = append(vars, sysvarname)
|
||||||
|
|
||||||
|
// Go function header.
|
||||||
|
outlist := strings.Join(out, ", ")
|
||||||
|
if outlist != "" {
|
||||||
|
outlist = fmt.Sprintf(" (%s)", outlist)
|
||||||
|
}
|
||||||
|
if text != "" {
|
||||||
|
text += "\n"
|
||||||
|
}
|
||||||
|
text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outlist)
|
||||||
|
|
||||||
|
// Check if err return available
|
||||||
|
errvar := ""
|
||||||
|
for _, param := range out {
|
||||||
|
p := parseParam(param)
|
||||||
|
if p.Type == "error" {
|
||||||
|
errvar = p.Name
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare arguments to Syscall.
|
||||||
|
var args []string
|
||||||
|
n := 0
|
||||||
|
for _, param := range in {
|
||||||
|
p := parseParam(param)
|
||||||
|
if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil {
|
||||||
|
args = append(args, "uintptr(unsafe.Pointer("+p.Name+"))")
|
||||||
|
} else if p.Type == "string" && errvar != "" {
|
||||||
|
text += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype)
|
||||||
|
text += fmt.Sprintf("\t_p%d, %s = %s(%s)\n", n, errvar, strconvfunc, p.Name)
|
||||||
|
text += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar)
|
||||||
|
args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n))
|
||||||
|
n++
|
||||||
|
} else if p.Type == "string" {
|
||||||
|
fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n")
|
||||||
|
text += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype)
|
||||||
|
text += fmt.Sprintf("\t_p%d, _ = %s(%s)\n", n, strconvfunc, p.Name)
|
||||||
|
args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n))
|
||||||
|
n++
|
||||||
|
} else if s := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); s != nil {
|
||||||
|
// Convert slice into pointer, length.
|
||||||
|
// Have to be careful not to take address of &a[0] if len == 0:
|
||||||
|
// pass nil in that case.
|
||||||
|
text += fmt.Sprintf("\tvar _p%d *%s\n", n, s[1])
|
||||||
|
text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name)
|
||||||
|
args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n), fmt.Sprintf("uintptr(len(%s))", p.Name))
|
||||||
|
n++
|
||||||
|
} else if p.Type == "int64" && endianness != "" {
|
||||||
|
if endianness == "big-endian" {
|
||||||
|
args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name))
|
||||||
|
} else {
|
||||||
|
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name))
|
||||||
|
}
|
||||||
|
} else if p.Type == "bool" {
|
||||||
|
text += fmt.Sprintf("\tvar _p%d uint32\n", n)
|
||||||
|
text += fmt.Sprintf("\tif %s {\n\t\t_p%d = 1\n\t} else {\n\t\t_p%d = 0\n\t}\n", p.Name, n, n)
|
||||||
|
args = append(args, fmt.Sprintf("uintptr(_p%d)", n))
|
||||||
|
n++
|
||||||
|
} else {
|
||||||
|
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nargs := len(args)
|
||||||
|
|
||||||
|
// Determine which form to use; pad args with zeros.
|
||||||
|
asm := "sysvicall6"
|
||||||
|
if nonblock != nil {
|
||||||
|
asm = "rawSysvicall6"
|
||||||
|
}
|
||||||
|
if len(args) <= 6 {
|
||||||
|
for len(args) < 6 {
|
||||||
|
args = append(args, "0")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: too many arguments to system call\n", path)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual call.
|
||||||
|
arglist := strings.Join(args, ", ")
|
||||||
|
call := fmt.Sprintf("%s(uintptr(unsafe.Pointer(&%s)), %d, %s)", asm, sysvarname, nargs, arglist)
|
||||||
|
|
||||||
|
// Assign return values.
|
||||||
|
body := ""
|
||||||
|
ret := []string{"_", "_", "_"}
|
||||||
|
doErrno := false
|
||||||
|
for i := 0; i < len(out); i++ {
|
||||||
|
p := parseParam(out[i])
|
||||||
|
reg := ""
|
||||||
|
if p.Name == "err" {
|
||||||
|
reg = "e1"
|
||||||
|
ret[2] = reg
|
||||||
|
doErrno = true
|
||||||
|
} else {
|
||||||
|
reg = fmt.Sprintf("r%d", i)
|
||||||
|
ret[i] = reg
|
||||||
|
}
|
||||||
|
if p.Type == "bool" {
|
||||||
|
reg = fmt.Sprintf("%d != 0", reg)
|
||||||
|
}
|
||||||
|
if p.Type == "int64" && endianness != "" {
|
||||||
|
// 64-bit number in r1:r0 or r0:r1.
|
||||||
|
if i+2 > len(out) {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: not enough registers for int64 return\n", path)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if endianness == "big-endian" {
|
||||||
|
reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i, i+1)
|
||||||
|
} else {
|
||||||
|
reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i+1, i)
|
||||||
|
}
|
||||||
|
ret[i] = fmt.Sprintf("r%d", i)
|
||||||
|
ret[i+1] = fmt.Sprintf("r%d", i+1)
|
||||||
|
}
|
||||||
|
if reg != "e1" {
|
||||||
|
body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ret[0] == "_" && ret[1] == "_" && ret[2] == "_" {
|
||||||
|
text += fmt.Sprintf("\t%s\n", call)
|
||||||
|
} else {
|
||||||
|
text += fmt.Sprintf("\t%s, %s, %s := %s\n", ret[0], ret[1], ret[2], call)
|
||||||
|
}
|
||||||
|
text += body
|
||||||
|
|
||||||
|
if doErrno {
|
||||||
|
text += "\tif e1 != 0 {\n"
|
||||||
|
text += "\t\terr = e1\n"
|
||||||
|
text += "\t}\n"
|
||||||
|
}
|
||||||
|
text += "\treturn\n"
|
||||||
|
text += "}\n"
|
||||||
|
}
|
||||||
|
if err := s.Err(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
file.Close()
|
||||||
|
}
|
||||||
|
imp := ""
|
||||||
|
if pack != "unix" {
|
||||||
|
imp = "import \"golang.org/x/sys/unix\"\n"
|
||||||
|
|
||||||
|
}
|
||||||
|
vardecls := "\t" + strings.Join(vars, ",\n\t")
|
||||||
|
vardecls += " syscallFunc"
|
||||||
|
fmt.Printf(srcTemplate, cmdLine(), buildTags(), pack, imp, dynimports, linknames, vardecls, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
const srcTemplate = `// %s
|
||||||
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
|
// +build %s
|
||||||
|
|
||||||
|
package %s
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
%s
|
||||||
|
%s
|
||||||
|
%s
|
||||||
|
var (
|
||||||
|
%s
|
||||||
|
)
|
||||||
|
|
||||||
|
%s
|
||||||
|
`
|
|
@ -1,294 +0,0 @@
|
||||||
#!/usr/bin/env perl
|
|
||||||
# Copyright 2009 The Go Authors. All rights reserved.
|
|
||||||
# Use of this source code is governed by a BSD-style
|
|
||||||
# license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
# This program reads a file containing function prototypes
|
|
||||||
# (like syscall_solaris.go) and generates system call bodies.
|
|
||||||
# The prototypes are marked by lines beginning with "//sys"
|
|
||||||
# and read like func declarations if //sys is replaced by func, but:
|
|
||||||
# * The parameter lists must give a name for each argument.
|
|
||||||
# This includes return parameters.
|
|
||||||
# * The parameter lists must give a type for each argument:
|
|
||||||
# the (x, y, z int) shorthand is not allowed.
|
|
||||||
# * If the return parameter is an error number, it must be named err.
|
|
||||||
# * If go func name needs to be different than its libc name,
|
|
||||||
# * or the function is not in libc, name could be specified
|
|
||||||
# * at the end, after "=" sign, like
|
|
||||||
# //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV);
|
|
||||||
my $errors = 0;
|
|
||||||
my $_32bit = "";
|
|
||||||
my $tags = ""; # build tags
|
|
||||||
|
|
||||||
binmode STDOUT;
|
|
||||||
|
|
||||||
if($ARGV[0] eq "-b32") {
|
|
||||||
$_32bit = "big-endian";
|
|
||||||
shift;
|
|
||||||
} elsif($ARGV[0] eq "-l32") {
|
|
||||||
$_32bit = "little-endian";
|
|
||||||
shift;
|
|
||||||
}
|
|
||||||
if($ARGV[0] eq "-tags") {
|
|
||||||
shift;
|
|
||||||
$tags = $ARGV[0];
|
|
||||||
shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($ARGV[0] =~ /^-/) {
|
|
||||||
print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [-tags x,y] [file ...]\n";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub parseparamlist($) {
|
|
||||||
my ($list) = @_;
|
|
||||||
$list =~ s/^\s*//;
|
|
||||||
$list =~ s/\s*$//;
|
|
||||||
if($list eq "") {
|
|
||||||
return ();
|
|
||||||
}
|
|
||||||
return split(/\s*,\s*/, $list);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub parseparam($) {
|
|
||||||
my ($p) = @_;
|
|
||||||
if($p !~ /^(\S*) (\S*)$/) {
|
|
||||||
print STDERR "$ARGV:$.: malformed parameter: $p\n";
|
|
||||||
$errors = 1;
|
|
||||||
return ("xx", "int");
|
|
||||||
}
|
|
||||||
return ($1, $2);
|
|
||||||
}
|
|
||||||
|
|
||||||
my $package = "";
|
|
||||||
my $text = "";
|
|
||||||
my $dynimports = "";
|
|
||||||
my $linknames = "";
|
|
||||||
my @vars = ();
|
|
||||||
while(<>) {
|
|
||||||
chomp;
|
|
||||||
s/\s+/ /g;
|
|
||||||
s/^\s+//;
|
|
||||||
s/\s+$//;
|
|
||||||
$package = $1 if !$package && /^package (\S+)$/;
|
|
||||||
my $nonblock = /^\/\/sysnb /;
|
|
||||||
next if !/^\/\/sys / && !$nonblock;
|
|
||||||
|
|
||||||
# Line must be of the form
|
|
||||||
# func Open(path string, mode int, perm int) (fd int, err error)
|
|
||||||
# Split into name, in params, out params.
|
|
||||||
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
|
|
||||||
print STDERR "$ARGV:$.: malformed //sys declaration\n";
|
|
||||||
$errors = 1;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
|
|
||||||
|
|
||||||
# Split argument lists on comma.
|
|
||||||
my @in = parseparamlist($in);
|
|
||||||
my @out = parseparamlist($out);
|
|
||||||
|
|
||||||
# Try in vain to keep people from editing this file.
|
|
||||||
# The theory is that they jump into the middle of the file
|
|
||||||
# without reading the header.
|
|
||||||
$text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
|
|
||||||
|
|
||||||
# So file name.
|
|
||||||
if($modname eq "") {
|
|
||||||
$modname = "libc";
|
|
||||||
}
|
|
||||||
|
|
||||||
# System call name.
|
|
||||||
if($sysname eq "") {
|
|
||||||
$sysname = "$func";
|
|
||||||
}
|
|
||||||
|
|
||||||
# System call pointer variable name.
|
|
||||||
my $sysvarname = "proc$sysname";
|
|
||||||
|
|
||||||
my $strconvfunc = "BytePtrFromString";
|
|
||||||
my $strconvtype = "*byte";
|
|
||||||
|
|
||||||
$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase.
|
|
||||||
|
|
||||||
# Runtime import of function to allow cross-platform builds.
|
|
||||||
$dynimports .= "//go:cgo_import_dynamic libc_${sysname} ${sysname} \"$modname.so\"\n";
|
|
||||||
# Link symbol to proc address variable.
|
|
||||||
$linknames .= "//go:linkname ${sysvarname} libc_${sysname}\n";
|
|
||||||
# Library proc address variable.
|
|
||||||
push @vars, $sysvarname;
|
|
||||||
|
|
||||||
# Go function header.
|
|
||||||
$out = join(', ', @out);
|
|
||||||
if($out ne "") {
|
|
||||||
$out = " ($out)";
|
|
||||||
}
|
|
||||||
if($text ne "") {
|
|
||||||
$text .= "\n"
|
|
||||||
}
|
|
||||||
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out;
|
|
||||||
|
|
||||||
# Check if err return available
|
|
||||||
my $errvar = "";
|
|
||||||
foreach my $p (@out) {
|
|
||||||
my ($name, $type) = parseparam($p);
|
|
||||||
if($type eq "error") {
|
|
||||||
$errvar = $name;
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Prepare arguments to Syscall.
|
|
||||||
my @args = ();
|
|
||||||
my $n = 0;
|
|
||||||
foreach my $p (@in) {
|
|
||||||
my ($name, $type) = parseparam($p);
|
|
||||||
if($type =~ /^\*/) {
|
|
||||||
push @args, "uintptr(unsafe.Pointer($name))";
|
|
||||||
} elsif($type eq "string" && $errvar ne "") {
|
|
||||||
$text .= "\tvar _p$n $strconvtype\n";
|
|
||||||
$text .= "\t_p$n, $errvar = $strconvfunc($name)\n";
|
|
||||||
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
|
|
||||||
push @args, "uintptr(unsafe.Pointer(_p$n))";
|
|
||||||
$n++;
|
|
||||||
} elsif($type eq "string") {
|
|
||||||
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
|
|
||||||
$text .= "\tvar _p$n $strconvtype\n";
|
|
||||||
$text .= "\t_p$n, _ = $strconvfunc($name)\n";
|
|
||||||
push @args, "uintptr(unsafe.Pointer(_p$n))";
|
|
||||||
$n++;
|
|
||||||
} elsif($type =~ /^\[\](.*)/) {
|
|
||||||
# Convert slice into pointer, length.
|
|
||||||
# Have to be careful not to take address of &a[0] if len == 0:
|
|
||||||
# pass nil in that case.
|
|
||||||
$text .= "\tvar _p$n *$1\n";
|
|
||||||
$text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n";
|
|
||||||
push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))";
|
|
||||||
$n++;
|
|
||||||
} elsif($type eq "int64" && $_32bit ne "") {
|
|
||||||
if($_32bit eq "big-endian") {
|
|
||||||
push @args, "uintptr($name >> 32)", "uintptr($name)";
|
|
||||||
} else {
|
|
||||||
push @args, "uintptr($name)", "uintptr($name >> 32)";
|
|
||||||
}
|
|
||||||
} elsif($type eq "bool") {
|
|
||||||
$text .= "\tvar _p$n uint32\n";
|
|
||||||
$text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n";
|
|
||||||
push @args, "uintptr(_p$n)";
|
|
||||||
$n++;
|
|
||||||
} else {
|
|
||||||
push @args, "uintptr($name)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
my $nargs = @args;
|
|
||||||
|
|
||||||
# Determine which form to use; pad args with zeros.
|
|
||||||
my $asm = "sysvicall6";
|
|
||||||
if ($nonblock) {
|
|
||||||
$asm = "rawSysvicall6";
|
|
||||||
}
|
|
||||||
if(@args <= 6) {
|
|
||||||
while(@args < 6) {
|
|
||||||
push @args, "0";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print STDERR "$ARGV:$.: too many arguments to system call\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
# Actual call.
|
|
||||||
my $args = join(', ', @args);
|
|
||||||
my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)";
|
|
||||||
|
|
||||||
# Assign return values.
|
|
||||||
my $body = "";
|
|
||||||
my $failexpr = "";
|
|
||||||
my @ret = ("_", "_", "_");
|
|
||||||
my @pout= ();
|
|
||||||
my $do_errno = 0;
|
|
||||||
for(my $i=0; $i<@out; $i++) {
|
|
||||||
my $p = $out[$i];
|
|
||||||
my ($name, $type) = parseparam($p);
|
|
||||||
my $reg = "";
|
|
||||||
if($name eq "err") {
|
|
||||||
$reg = "e1";
|
|
||||||
$ret[2] = $reg;
|
|
||||||
$do_errno = 1;
|
|
||||||
} else {
|
|
||||||
$reg = sprintf("r%d", $i);
|
|
||||||
$ret[$i] = $reg;
|
|
||||||
}
|
|
||||||
if($type eq "bool") {
|
|
||||||
$reg = "$reg != 0";
|
|
||||||
}
|
|
||||||
if($type eq "int64" && $_32bit ne "") {
|
|
||||||
# 64-bit number in r1:r0 or r0:r1.
|
|
||||||
if($i+2 > @out) {
|
|
||||||
print STDERR "$ARGV:$.: not enough registers for int64 return\n";
|
|
||||||
}
|
|
||||||
if($_32bit eq "big-endian") {
|
|
||||||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
|
|
||||||
} else {
|
|
||||||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
|
|
||||||
}
|
|
||||||
$ret[$i] = sprintf("r%d", $i);
|
|
||||||
$ret[$i+1] = sprintf("r%d", $i+1);
|
|
||||||
}
|
|
||||||
if($reg ne "e1") {
|
|
||||||
$body .= "\t$name = $type($reg)\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
|
|
||||||
$text .= "\t$call\n";
|
|
||||||
} else {
|
|
||||||
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
|
|
||||||
}
|
|
||||||
$text .= $body;
|
|
||||||
|
|
||||||
if ($do_errno) {
|
|
||||||
$text .= "\tif e1 != 0 {\n";
|
|
||||||
$text .= "\t\terr = e1\n";
|
|
||||||
$text .= "\t}\n";
|
|
||||||
}
|
|
||||||
$text .= "\treturn\n";
|
|
||||||
$text .= "}\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if($errors) {
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
print <<EOF;
|
|
||||||
// $cmdline
|
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
|
||||||
|
|
||||||
// +build $tags
|
|
||||||
|
|
||||||
package $package
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
EOF
|
|
||||||
|
|
||||||
print "import \"golang.org/x/sys/unix\"\n" if $package ne "unix";
|
|
||||||
|
|
||||||
my $vardecls = "\t" . join(",\n\t", @vars);
|
|
||||||
$vardecls .= " syscallFunc";
|
|
||||||
|
|
||||||
chomp($_=<<EOF);
|
|
||||||
|
|
||||||
$dynimports
|
|
||||||
$linknames
|
|
||||||
var (
|
|
||||||
$vardecls
|
|
||||||
)
|
|
||||||
|
|
||||||
$text
|
|
||||||
EOF
|
|
||||||
print $_;
|
|
||||||
exit 0;
|
|
|
@ -25,8 +25,8 @@ func cmsgAlignOf(salen int) int {
|
||||||
if SizeofPtr == 8 {
|
if SizeofPtr == 8 {
|
||||||
salign = 4
|
salign = 4
|
||||||
}
|
}
|
||||||
case "openbsd":
|
case "netbsd", "openbsd":
|
||||||
// OpenBSD armv7 requires 64-bit alignment.
|
// NetBSD and OpenBSD armv7 require 64-bit alignment.
|
||||||
if runtime.GOARCH == "arm" {
|
if runtime.GOARCH == "arm" {
|
||||||
salign = 8
|
salign = 8
|
||||||
}
|
}
|
||||||
|
|
|
@ -545,3 +545,5 @@ func Poll(fds []PollFd, timeout int) (n int, err error) {
|
||||||
//sys gettimeofday(tv *Timeval, tzp *Timezone) (err error)
|
//sys gettimeofday(tv *Timeval, tzp *Timezone) (err error)
|
||||||
//sysnb Time(t *Time_t) (tt Time_t, err error)
|
//sysnb Time(t *Time_t) (tt Time_t, err error)
|
||||||
//sys Utime(path string, buf *Utimbuf) (err error)
|
//sys Utime(path string, buf *Utimbuf) (err error)
|
||||||
|
|
||||||
|
//sys Getsystemcfg(label int) (n uint64)
|
||||||
|
|
|
@ -144,6 +144,23 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) (
|
||||||
|
|
||||||
//sys getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error)
|
//sys getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error)
|
||||||
|
|
||||||
|
func SysctlClockinfo(name string) (*Clockinfo, error) {
|
||||||
|
mib, err := sysctlmib(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n := uintptr(SizeofClockinfo)
|
||||||
|
var ci Clockinfo
|
||||||
|
if err := sysctl(mib, (*byte)(unsafe.Pointer(&ci)), &n, nil, 0); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n != SizeofClockinfo {
|
||||||
|
return nil, EIO
|
||||||
|
}
|
||||||
|
return &ci, nil
|
||||||
|
}
|
||||||
|
|
||||||
//sysnb pipe() (r int, w int, err error)
|
//sysnb pipe() (r int, w int, err error)
|
||||||
|
|
||||||
func Pipe(p []int) (err error) {
|
func Pipe(p []int) (err error) {
|
||||||
|
|
|
@ -39,6 +39,20 @@ func Creat(path string, mode uint32) (fd int, err error) {
|
||||||
return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
|
return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sys FanotifyInit(flags uint, event_f_flags uint) (fd int, err error)
|
||||||
|
//sys fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error)
|
||||||
|
|
||||||
|
func FanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname string) (err error) {
|
||||||
|
if pathname == "" {
|
||||||
|
return fanotifyMark(fd, flags, mask, dirFd, nil)
|
||||||
|
}
|
||||||
|
p, err := BytePtrFromString(pathname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fanotifyMark(fd, flags, mask, dirFd, p)
|
||||||
|
}
|
||||||
|
|
||||||
//sys fchmodat(dirfd int, path string, mode uint32) (err error)
|
//sys fchmodat(dirfd int, path string, mode uint32) (err error)
|
||||||
|
|
||||||
func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
|
func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
|
||||||
|
@ -990,10 +1004,50 @@ func GetsockoptString(fd, level, opt int) (string, error) {
|
||||||
return string(buf[:vallen-1]), nil
|
return string(buf[:vallen-1]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetsockoptTpacketStats(fd, level, opt int) (*TpacketStats, error) {
|
||||||
|
var value TpacketStats
|
||||||
|
vallen := _Socklen(SizeofTpacketStats)
|
||||||
|
err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
||||||
|
return &value, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetsockoptTpacketStatsV3(fd, level, opt int) (*TpacketStatsV3, error) {
|
||||||
|
var value TpacketStatsV3
|
||||||
|
vallen := _Socklen(SizeofTpacketStatsV3)
|
||||||
|
err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
||||||
|
return &value, err
|
||||||
|
}
|
||||||
|
|
||||||
func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
|
func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
|
||||||
return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
|
return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetsockoptPacketMreq(fd, level, opt int, mreq *PacketMreq) error {
|
||||||
|
return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetsockoptSockFprog attaches a classic BPF or an extended BPF program to a
|
||||||
|
// socket to filter incoming packets. See 'man 7 socket' for usage information.
|
||||||
|
func SetsockoptSockFprog(fd, level, opt int, fprog *SockFprog) error {
|
||||||
|
return setsockopt(fd, level, opt, unsafe.Pointer(fprog), unsafe.Sizeof(*fprog))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetsockoptCanRawFilter(fd, level, opt int, filter []CanFilter) error {
|
||||||
|
var p unsafe.Pointer
|
||||||
|
if len(filter) > 0 {
|
||||||
|
p = unsafe.Pointer(&filter[0])
|
||||||
|
}
|
||||||
|
return setsockopt(fd, level, opt, p, uintptr(len(filter)*SizeofCanFilter))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetsockoptTpacketReq(fd, level, opt int, tp *TpacketReq) error {
|
||||||
|
return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetsockoptTpacketReq3(fd, level, opt int, tp *TpacketReq3) error {
|
||||||
|
return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp))
|
||||||
|
}
|
||||||
|
|
||||||
// Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html)
|
// Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html)
|
||||||
|
|
||||||
// KeyctlInt calls keyctl commands in which each argument is an int.
|
// KeyctlInt calls keyctl commands in which each argument is an int.
|
||||||
|
|
|
@ -19,12 +19,18 @@ func setTimeval(sec, usec int64) Timeval {
|
||||||
return Timeval{Sec: int32(sec), Usec: int32(usec)}
|
return Timeval{Sec: int32(sec), Usec: int32(usec)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sysnb pipe(p *[2]_C_int) (err error)
|
||||||
|
|
||||||
func Pipe(p []int) (err error) {
|
func Pipe(p []int) (err error) {
|
||||||
if len(p) != 2 {
|
if len(p) != 2 {
|
||||||
return EINVAL
|
return EINVAL
|
||||||
}
|
}
|
||||||
var pp [2]_C_int
|
var pp [2]_C_int
|
||||||
|
// Try pipe2 first for Android O, then try pipe for kernel 2.6.23.
|
||||||
err = pipe2(&pp, 0)
|
err = pipe2(&pp, 0)
|
||||||
|
if err == ENOSYS {
|
||||||
|
err = pipe(&pp)
|
||||||
|
}
|
||||||
p[0] = int(pp[0])
|
p[0] = int(pp[0])
|
||||||
p[1] = int(pp[1])
|
p[1] = int(pp[1])
|
||||||
return
|
return
|
||||||
|
|
|
@ -208,3 +208,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) {
|
||||||
}
|
}
|
||||||
return ppoll(&fds[0], len(fds), ts, nil)
|
return ppoll(&fds[0], len(fds), ts, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
|
||||||
|
|
||||||
|
func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error {
|
||||||
|
cmdlineLen := len(cmdline)
|
||||||
|
if cmdlineLen > 0 {
|
||||||
|
// Account for the additional NULL byte added by
|
||||||
|
// BytePtrFromString in kexecFileLoad. The kexec_file_load
|
||||||
|
// syscall expects a NULL-terminated string.
|
||||||
|
cmdlineLen++
|
||||||
|
}
|
||||||
|
return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
|
||||||
|
}
|
||||||
|
|
|
@ -211,3 +211,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) {
|
||||||
func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
|
func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
|
||||||
return Renameat2(olddirfd, oldpath, newdirfd, newpath, 0)
|
return Renameat2(olddirfd, oldpath, newdirfd, newpath, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
|
||||||
|
|
||||||
|
func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error {
|
||||||
|
cmdlineLen := len(cmdline)
|
||||||
|
if cmdlineLen > 0 {
|
||||||
|
// Account for the additional NULL byte added by
|
||||||
|
// BytePtrFromString in kexecFileLoad. The kexec_file_load
|
||||||
|
// syscall expects a NULL-terminated string.
|
||||||
|
cmdlineLen++
|
||||||
|
}
|
||||||
|
return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
|
||||||
|
}
|
||||||
|
|
|
@ -43,6 +43,23 @@ func nametomib(name string) (mib []_C_int, err error) {
|
||||||
return nil, EINVAL
|
return nil, EINVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SysctlClockinfo(name string) (*Clockinfo, error) {
|
||||||
|
mib, err := sysctlmib(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n := uintptr(SizeofClockinfo)
|
||||||
|
var ci Clockinfo
|
||||||
|
if err := sysctl(mib, (*byte)(unsafe.Pointer(&ci)), &n, nil, 0); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n != SizeofClockinfo {
|
||||||
|
return nil, EIO
|
||||||
|
}
|
||||||
|
return &ci, nil
|
||||||
|
}
|
||||||
|
|
||||||
func SysctlUvmexp(name string) (*Uvmexp, error) {
|
func SysctlUvmexp(name string) (*Uvmexp, error) {
|
||||||
mib, err := sysctlmib(name)
|
mib, err := sysctlmib(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -28,6 +28,11 @@ var (
|
||||||
errENOENT error = syscall.ENOENT
|
errENOENT error = syscall.ENOENT
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
signalNameMapOnce sync.Once
|
||||||
|
signalNameMap map[string]syscall.Signal
|
||||||
|
)
|
||||||
|
|
||||||
// errnoErr returns common boxed Errno values, to prevent
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
// allocations at runtime.
|
// allocations at runtime.
|
||||||
func errnoErr(e syscall.Errno) error {
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
@ -66,6 +71,19 @@ func SignalName(s syscall.Signal) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignalNum returns the syscall.Signal for signal named s,
|
||||||
|
// or 0 if a signal with such name is not found.
|
||||||
|
// The signal name should start with "SIG".
|
||||||
|
func SignalNum(s string) syscall.Signal {
|
||||||
|
signalNameMapOnce.Do(func() {
|
||||||
|
signalNameMap = make(map[string]syscall.Signal)
|
||||||
|
for _, signal := range signalList {
|
||||||
|
signalNameMap[signal.name] = signal.num
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return signalNameMap[s]
|
||||||
|
}
|
||||||
|
|
||||||
// clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte.
|
// clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte.
|
||||||
func clen(n []byte) int {
|
func clen(n []byte) int {
|
||||||
i := bytes.IndexByte(n, 0)
|
i := bytes.IndexByte(n, 0)
|
||||||
|
@ -276,6 +294,13 @@ func GetsockoptTimeval(fd, level, opt int) (*Timeval, error) {
|
||||||
return &tv, err
|
return &tv, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetsockoptUint64(fd, level, opt int) (value uint64, err error) {
|
||||||
|
var n uint64
|
||||||
|
vallen := _Socklen(8)
|
||||||
|
err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
|
func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
|
||||||
var rsa RawSockaddrAny
|
var rsa RawSockaddrAny
|
||||||
var len _Socklen = SizeofSockaddrAny
|
var len _Socklen = SizeofSockaddrAny
|
||||||
|
@ -333,6 +358,10 @@ func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
|
||||||
return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))
|
return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetsockoptUint64(fd, level, opt int, value uint64) (err error) {
|
||||||
|
return setsockopt(fd, level, opt, unsafe.Pointer(&value), 8)
|
||||||
|
}
|
||||||
|
|
||||||
func Socket(domain, typ, proto int) (fd int, err error) {
|
func Socket(domain, typ, proto int) (fd int, err error) {
|
||||||
if domain == AF_INET6 && SocketDisableIPv6 {
|
if domain == AF_INET6 && SocketDisableIPv6 {
|
||||||
return -1, EAFNOSUPPORT
|
return -1, EAFNOSUPPORT
|
||||||
|
@ -377,3 +406,22 @@ func SetNonblock(fd int, nonblocking bool) (err error) {
|
||||||
func Exec(argv0 string, argv []string, envv []string) error {
|
func Exec(argv0 string, argv []string, envv []string) error {
|
||||||
return syscall.Exec(argv0, argv, envv)
|
return syscall.Exec(argv0, argv, envv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lutimes sets the access and modification times tv on path. If path refers to
|
||||||
|
// a symlink, it is not dereferenced and the timestamps are set on the symlink.
|
||||||
|
// If tv is nil, the access and modification times are set to the current time.
|
||||||
|
// Otherwise tv must contain exactly 2 elements, with access time as the first
|
||||||
|
// element and modification time as the second element.
|
||||||
|
func Lutimes(path string, tv []Timeval) error {
|
||||||
|
if tv == nil {
|
||||||
|
return UtimesNanoAt(AT_FDCWD, path, nil, AT_SYMLINK_NOFOLLOW)
|
||||||
|
}
|
||||||
|
if len(tv) != 2 {
|
||||||
|
return EINVAL
|
||||||
|
}
|
||||||
|
ts := []Timespec{
|
||||||
|
NsecToTimespec(TimevalToNsec(tv[0])),
|
||||||
|
NsecToTimespec(TimevalToNsec(tv[1])),
|
||||||
|
}
|
||||||
|
return UtimesNanoAt(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW)
|
||||||
|
}
|
||||||
|
|
|
@ -275,3 +275,9 @@ const (
|
||||||
// uname
|
// uname
|
||||||
|
|
||||||
type Utsname C.struct_utsname
|
type Utsname C.struct_utsname
|
||||||
|
|
||||||
|
// Clockinfo
|
||||||
|
|
||||||
|
const SizeofClockinfo = C.sizeof_struct_clockinfo
|
||||||
|
|
||||||
|
type Clockinfo C.struct_clockinfo
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue