diff --git a/go.mod b/go.mod index 90783c70..9b677c35 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.24.0 require ( github.com/NVIDIA/go-nvlib v0.8.1 github.com/NVIDIA/go-nvml v0.13.0-1 + github.com/NVIDIA/nvidia-container-toolkit v1.18.0 github.com/coreos/go-systemd/v22 v22.6.0 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.11.1 @@ -14,12 +15,14 @@ require ( k8s.io/apimachinery v0.33.3 k8s.io/client-go v0.33.3 sigs.k8s.io/yaml v1.6.0 + tags.cncf.io/container-device-interface v1.0.1 ) require ( github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect @@ -36,16 +39,20 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/runtime-spec v1.2.1 // indirect + github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect + golang.org/x/mod v0.29.0 // indirect golang.org/x/net v0.38.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect - golang.org/x/sys v0.31.0 // indirect + golang.org/x/sys v0.37.0 // indirect golang.org/x/term v0.30.0 // indirect golang.org/x/text v0.23.0 // indirect golang.org/x/time v0.9.0 // indirect @@ -59,4 +66,7 @@ require ( sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + tags.cncf.io/container-device-interface/specs-go v1.0.0 // indirect ) + +replace github.com/NVIDIA/nvidia-container-toolkit v1.18.0 => ../container-toolkit diff --git a/go.sum b/go.sum index 9ba13ee0..a700ecaa 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/NVIDIA/go-nvlib v0.8.1 h1:OPEHVvn3zcV5OXB68A7WRpeCnYMRSPl7LdeJH/d3gZI github.com/NVIDIA/go-nvlib v0.8.1/go.mod h1:7mzx9FSdO9fXWP9NKuZmWkCwhkEcSWQFe2tmFwtLb9c= github.com/NVIDIA/go-nvml v0.13.0-1 h1:OLX8Jq3dONuPOQPC7rndB6+iDmDakw0XTYgzMxObkEw= github.com/NVIDIA/go-nvml v0.13.0-1/go.mod h1:+KNA7c7gIBH7SKSJ1ntlwkfN80zdx8ovl4hrK3LmPt4= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= @@ -13,6 +15,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= @@ -39,8 +43,14 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -56,17 +66,27 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww= +github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 h1:DmNGcqH3WDbV5k8OJ+esPWbqUOX5rMLR2PMvziDMJi0= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI= +github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -76,6 +96,7 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -85,6 +106,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -92,10 +114,20 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/urfave/cli v1.19.1/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -111,6 +143,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -124,10 +158,12 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -140,8 +176,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -182,3 +218,7 @@ sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vt sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= +tags.cncf.io/container-device-interface v1.0.1 h1:KqQDr4vIlxwfYh0Ed/uJGVgX+CHAkahrgabg6Q8GYxc= +tags.cncf.io/container-device-interface v1.0.1/go.mod h1:JojJIOeW3hNbcnOH2q0NrWNha/JuHoDZcmYxAZwb2i0= +tags.cncf.io/container-device-interface/specs-go v1.0.0 h1:8gLw29hH1ZQP9K1YtAzpvkHCjjyIxHZYzBAvlQ+0vD8= +tags.cncf.io/container-device-interface/specs-go v1.0.0/go.mod h1:u86hoFWqnh3hWz3esofRFKbI261bUlvUfLKGrDhJkgQ= diff --git a/pkg/mig/reconfigure/reconfigure.go b/pkg/mig/reconfigure/reconfigure.go index 8d91f56f..b5da1762 100644 --- a/pkg/mig/reconfigure/reconfigure.go +++ b/pkg/mig/reconfigure/reconfigure.go @@ -29,6 +29,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" + "tags.cncf.io/container-device-interface/pkg/cdi" + + devicenodes "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/system/create-device-nodes" + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi" + transformroot "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root" "github.com/NVIDIA/mig-parted/internal/systemd" ) @@ -468,11 +473,13 @@ func (r *Reconfigure) applyMigConfig() error { func (r *Reconfigure) handleCDI() error { log.Info("Creating NVIDIA control device nodes") - // TODO: Instead of shelling out, we need to invoke the method via Go. The Toolkit code needs to be refactored first. - cmd := exec.Command("nvidia-ctk", "system", "create-device-nodes", "--control-devices", "--dev-root="+r.opts.DevRootCtrPath) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { + + // TODO: Instead of abusing CLI command we generate here, we should expose + // this API and use that instead. This would require refactoring in the + // toolkit. + cmd := devicenodes.NewCommand(log.StandardLogger()) + err := cmd.Run(context.Background(), []string{"--control-devices", "--dev-root" + r.opts.DevRootCtrPath}) + if err != nil { return fmt.Errorf("failed to create control device nodes: %w", err) } @@ -641,59 +648,48 @@ func (r *Reconfigure) runNvidiaSMI() error { func (r *Reconfigure) createCDISpec() error { log.Info("Creating management CDI spec (simplified implementation)") - cdiGenerateCommand := exec.Command("nvidia-ctk", "cdi", "generate", - "--driver-root="+r.opts.DriverRootCtrPath, - "--dev-root="+r.opts.DevRootCtrPath, - "--vendor=management.nvidia.com", - "--class=gpu", - "--nvidia-cdi-hook-path="+r.opts.NvidiaCDIHookPath, - ) + if !r.opts.CDIEnabled { + return nil + } - stdout1, err := cdiGenerateCommand.StdoutPipe() + cdilib, err := nvcdi.New( + // TODO: We may want to switch to klog for logging here. + nvcdi.WithLogger(log.StandardLogger()), + nvcdi.WithMode(nvcdi.ModeManagement), + nvcdi.WithDriverRoot(r.opts.DriverRootCtrPath), + nvcdi.WithDevRoot(r.opts.DevRootCtrPath), + nvcdi.WithNVIDIACDIHookPath(r.opts.NvidiaCDIHookPath), + nvcdi.WithVendor("management.nvidia.com"), + nvcdi.WithClass("gpu"), + ) if err != nil { - return fmt.Errorf("failed to get stdout pipe for the nvidia-ctk command: %w", err) + return fmt.Errorf("failed to create CDI library for management containers: %v", err) } - cdiTransformDriverRootCommand := exec.Command("nvidia-ctk", "cdi", "transform", "root", - "--from="+r.opts.DriverRootCtrPath, - "--to="+r.opts.DriverRoot, - "--input=-") - cdiTransformDriverRootCommand.Stdin = stdout1 - - stdout2, err := cdiTransformDriverRootCommand.StdoutPipe() + spec, err := cdilib.GetSpec() if err != nil { - return fmt.Errorf("failed to get stdout pipe for the cdiTransformDriverRootCommand: %w", err) + return fmt.Errorf("failed to genereate CDI spec for management containers: %v", err) } - cdiTransformDevRootCommand := exec.Command("nvidia-ctk", "cdi", "transform", "root", - "--from="+r.opts.DevRootCtrPath, - "--to="+r.opts.DevRoot, - "--input=-", - "--output=/var/run/cdi/management.nvidia.com-gpu.yaml") - - cdiTransformDevRootCommand.Stdin = stdout2 - - err = cdiGenerateCommand.Start() - if err != nil { - return fmt.Errorf("cmd.Start error for cdiGenerateCommand: %w", err) + transformer := transformroot.NewDriverTransformer( + transformroot.WithDriverRoot(r.opts.DriverRootCtrPath), + transformroot.WithTargetDriverRoot(r.opts.DriverRoot), + transformroot.WithDevRoot(r.opts.DevRootCtrPath), + transformroot.WithTargetDevRoot(r.opts.DevRoot), + ) + if err := transformer.Transform(spec.Raw()); err != nil { + return fmt.Errorf("failed to transform driver root in CDI spec: %v", err) } - err = cdiTransformDriverRootCommand.Start() + + name, err := cdi.GenerateNameForSpec(spec.Raw()) if err != nil { - return fmt.Errorf("cmd.Start error for cdiTransformDriverRootCommand: %w", err) + return fmt.Errorf("failed to generate CDI name for management containers: %v", err) } - err = cdiTransformDevRootCommand.Start() + // TODO: Should this path be configurable? What's important is that this + // file path is the same as the one generated in the NVIDIA Container Toolkit. + err = spec.Save(filepath.Join("/var/run/cdi/", name)) if err != nil { - return fmt.Errorf("cmd.Start error for running cdiTransformDevRootCommand: %w", err) - } - - if err = cdiGenerateCommand.Wait(); err != nil { - return fmt.Errorf("cmd.Wait error for cdiGenerateCommand: %w", err) - } - if err = cdiTransformDriverRootCommand.Wait(); err != nil { - return fmt.Errorf("cmd.Wait error for cdiTransformDriverRootCommand: %w", err) - } - if err = cdiTransformDevRootCommand.Wait(); err != nil { - return fmt.Errorf("cmd.Wait error for cdiTransformDevRootCommand: %w", err) + return fmt.Errorf("failed to save CDI spec for management containers: %v", err) } return nil diff --git a/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/api.go b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/api.go new file mode 100644 index 00000000..bcc9cb69 --- /dev/null +++ b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/api.go @@ -0,0 +1,43 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package info + +// Interface provides the API to the info package. +type Interface interface { + PlatformResolver + PropertyExtractor +} + +// PlatformResolver defines a function to resolve the current platform. +type PlatformResolver interface { + ResolvePlatform() Platform +} + +// PropertyExtractor provides a set of functions to query capabilities of the +// system. +// +//go:generate moq -rm -fmt=goimports -out property-extractor_mock.go . PropertyExtractor +type PropertyExtractor interface { + HasDXCore() (bool, string) + HasNvml() (bool, string) + HasTegraFiles() (bool, string) + // Deprecated: Use HasTegraFiles instead. + IsTegraSystem() (bool, string) + // Deprecated: Use HasOnlyIntegratedGPUs + UsesOnlyNVGPUModule() (bool, string) + HasOnlyIntegratedGPUs() (bool, string) +} diff --git a/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/builder.go b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/builder.go new file mode 100644 index 00000000..61684407 --- /dev/null +++ b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/builder.go @@ -0,0 +1,78 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package info + +import ( + "github.com/NVIDIA/go-nvml/pkg/nvml" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/device" +) + +type infolib struct { + PropertyExtractor + PlatformResolver +} + +type options struct { + logger basicLogger + root root + nvmllib nvml.Interface + devicelib device.Interface + + platform Platform + propertyExtractor PropertyExtractor +} + +// New creates a new instance of the 'info' interface. +func New(opts ...Option) Interface { + o := &options{} + for _, opt := range opts { + opt(o) + } + if o.logger == nil { + o.logger = &nullLogger{} + } + if o.root == "" { + o.root = "/" + } + if o.nvmllib == nil { + o.nvmllib = nvml.New( + nvml.WithLibraryPath(o.root.tryResolveLibrary("libnvidia-ml.so.1")), + ) + } + if o.devicelib == nil { + o.devicelib = device.New(o.nvmllib) + } + if o.platform == "" { + o.platform = PlatformAuto + } + if o.propertyExtractor == nil { + o.propertyExtractor = &propertyExtractor{ + root: o.root, + nvmllib: o.nvmllib, + devicelib: o.devicelib, + } + } + return &infolib{ + PlatformResolver: &platformResolver{ + logger: o.logger, + platform: o.platform, + propertyExtractor: o.propertyExtractor, + }, + PropertyExtractor: o.propertyExtractor, + } +} diff --git a/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/logger.go b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/logger.go new file mode 100644 index 00000000..6a6f74ee --- /dev/null +++ b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/logger.go @@ -0,0 +1,28 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package info + +type basicLogger interface { + Debugf(string, ...interface{}) + Infof(string, ...interface{}) +} + +type nullLogger struct{} + +func (n *nullLogger) Debugf(string, ...interface{}) {} + +func (n *nullLogger) Infof(string, ...interface{}) {} diff --git a/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/options.go b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/options.go new file mode 100644 index 00000000..e05c2bf7 --- /dev/null +++ b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/options.go @@ -0,0 +1,70 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package info + +import ( + "github.com/NVIDIA/go-nvml/pkg/nvml" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/device" +) + +// Option defines a function for passing options to the New() call. +type Option func(*options) + +// WithDeviceLib sets the device library for the library. +func WithDeviceLib(devicelib device.Interface) Option { + return func(i *options) { + i.devicelib = devicelib + } +} + +// WithLogger sets the logger for the library. +func WithLogger(logger basicLogger) Option { + return func(i *options) { + i.logger = logger + } +} + +// WithNvmlLib sets the nvml library for the library. +func WithNvmlLib(nvmllib nvml.Interface) Option { + return func(i *options) { + i.nvmllib = nvmllib + } +} + +// WithRoot provides a Option to set the root of the 'info' interface. +func WithRoot(r string) Option { + return func(i *options) { + i.root = root(r) + } +} + +// WithPropertyExtractor provides an Option to set the PropertyExtractor +// interface implementation. +// This is predominantly used for testing. +func WithPropertyExtractor(propertyExtractor PropertyExtractor) Option { + return func(i *options) { + i.propertyExtractor = propertyExtractor + } +} + +// WithPlatform provides an option to set the platform explicitly. +func WithPlatform(platform Platform) Option { + return func(i *options) { + i.platform = platform + } +} diff --git a/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/property-extractor.go b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/property-extractor.go new file mode 100644 index 00000000..20204713 --- /dev/null +++ b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/property-extractor.go @@ -0,0 +1,161 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package info + +import ( + "fmt" + "os" + "strings" + + "github.com/NVIDIA/go-nvml/pkg/nvml" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/device" +) + +type propertyExtractor struct { + root root + nvmllib nvml.Interface + devicelib device.Interface +} + +var _ PropertyExtractor = &propertyExtractor{} + +// HasDXCore returns true if DXCore is detected on the system. +func (i *propertyExtractor) HasDXCore() (bool, string) { + const ( + libraryName = "libdxcore.so" + ) + if err := i.root.assertHasLibrary(libraryName); err != nil { + return false, fmt.Sprintf("could not load DXCore library: %v", err) + } + + return true, "found DXCore library" +} + +// HasNvml returns true if NVML is detected on the system. +func (i *propertyExtractor) HasNvml() (bool, string) { + const ( + libraryName = "libnvidia-ml.so.1" + ) + if err := i.root.assertHasLibrary(libraryName); err != nil { + return false, fmt.Sprintf("could not load NVML library: %v", err) + } + + return true, "found NVML library" +} + +// IsTegraSystem returns true if the system is detected as a Tegra-based system. +// Deprecated: Use HasTegraFiles instead. +func (i *propertyExtractor) IsTegraSystem() (bool, string) { + return i.HasTegraFiles() +} + +// HasTegraFiles returns true if tegra-based files are detected on the system. +func (i *propertyExtractor) HasTegraFiles() (bool, string) { + tegraReleaseFile := i.root.join("/etc/nv_tegra_release") + tegraFamilyFile := i.root.join("/sys/devices/soc0/family") + + if info, err := os.Stat(tegraReleaseFile); err == nil && !info.IsDir() { + return true, fmt.Sprintf("%v found", tegraReleaseFile) + } + + if info, err := os.Stat(tegraFamilyFile); err != nil || info.IsDir() { + return false, fmt.Sprintf("%v file not found", tegraFamilyFile) + } + + contents, err := os.ReadFile(tegraFamilyFile) + if err != nil { + return false, fmt.Sprintf("could not read %v", tegraFamilyFile) + } + + if strings.HasPrefix(strings.ToLower(string(contents)), "tegra") { + return true, fmt.Sprintf("%v has 'tegra' prefix", tegraFamilyFile) + } + + return false, fmt.Sprintf("%v has no 'tegra' prefix", tegraFamilyFile) +} + +// UsesOnlyNVGPUModule checks whether the only the nvgpu module is used. +// +// Deprecated: UsesOnlyNVGPUModule is deprecated, use HasOnlyIntegratedGPUs instead. +func (i *propertyExtractor) UsesOnlyNVGPUModule() (uses bool, reason string) { + return i.HasOnlyIntegratedGPUs() +} + +// HasOnlyIntegratedGPUs checks whether all GPUs are iGPUs that use NVML. +// +// As of Orin-based systems iGPUs also support limited NVML queries. +// In the absence of a robust API, we rely on heuristics to make this decision. +// +// The following device names are checked: +// +// GPU 0: Orin (nvgpu) (UUID: 54d0709b-558d-5a59-9c65-0c5fc14a21a4) +// GPU 0: NVIDIA Thor (UUID: 54d0709b-558d-5a59-9c65-0c5fc14a21a4) +// +// This function returns true if ALL devices are detected as iGPUs. +func (i *propertyExtractor) HasOnlyIntegratedGPUs() (uses bool, reason string) { + // We ensure that this function never panics + defer func() { + if err := recover(); err != nil { + uses = false + reason = fmt.Sprintf("panic: %v", err) + } + }() + + ret := i.nvmllib.Init() + if ret != nvml.SUCCESS { + return false, fmt.Sprintf("failed to initialize nvml: %v", ret) + } + defer func() { + _ = i.nvmllib.Shutdown() + }() + + var names []string + + err := i.devicelib.VisitDevices(func(i int, d device.Device) error { + name, ret := d.GetName() + if ret != nvml.SUCCESS { + return fmt.Errorf("device %v: %v", i, ret) + } + names = append(names, name) + return nil + }) + if err != nil { + return false, fmt.Sprintf("failed to get device names: %v", err) + } + + if len(names) == 0 { + return false, "no devices found" + } + + for _, name := range names { + if !isIntegratedGPUName(name) { + return false, fmt.Sprintf("device %q does not use nvgpu module", name) + } + } + return true, "all devices use nvgpu module" +} + +func isIntegratedGPUName(name string) bool { + if strings.Contains(name, "(nvgpu)") { + return true + } + if strings.Contains(name, "NVIDIA Thor") { + return true + } + return false +} diff --git a/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/property-extractor_mock.go b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/property-extractor_mock.go new file mode 100644 index 00000000..bd7d4135 --- /dev/null +++ b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/property-extractor_mock.go @@ -0,0 +1,252 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package info + +import ( + "sync" +) + +// Ensure, that PropertyExtractorMock does implement PropertyExtractor. +// If this is not the case, regenerate this file with moq. +var _ PropertyExtractor = &PropertyExtractorMock{} + +// PropertyExtractorMock is a mock implementation of PropertyExtractor. +// +// func TestSomethingThatUsesPropertyExtractor(t *testing.T) { +// +// // make and configure a mocked PropertyExtractor +// mockedPropertyExtractor := &PropertyExtractorMock{ +// HasDXCoreFunc: func() (bool, string) { +// panic("mock out the HasDXCore method") +// }, +// HasNvmlFunc: func() (bool, string) { +// panic("mock out the HasNvml method") +// }, +// HasOnlyIntegratedGPUsFunc: func() (bool, string) { +// panic("mock out the HasOnlyIntegratedGPUs method") +// }, +// HasTegraFilesFunc: func() (bool, string) { +// panic("mock out the HasTegraFiles method") +// }, +// IsTegraSystemFunc: func() (bool, string) { +// panic("mock out the IsTegraSystem method") +// }, +// UsesOnlyNVGPUModuleFunc: func() (bool, string) { +// panic("mock out the UsesOnlyNVGPUModule method") +// }, +// } +// +// // use mockedPropertyExtractor in code that requires PropertyExtractor +// // and then make assertions. +// +// } +type PropertyExtractorMock struct { + // HasDXCoreFunc mocks the HasDXCore method. + HasDXCoreFunc func() (bool, string) + + // HasNvmlFunc mocks the HasNvml method. + HasNvmlFunc func() (bool, string) + + // HasOnlyIntegratedGPUsFunc mocks the HasOnlyIntegratedGPUs method. + HasOnlyIntegratedGPUsFunc func() (bool, string) + + // HasTegraFilesFunc mocks the HasTegraFiles method. + HasTegraFilesFunc func() (bool, string) + + // IsTegraSystemFunc mocks the IsTegraSystem method. + IsTegraSystemFunc func() (bool, string) + + // UsesOnlyNVGPUModuleFunc mocks the UsesOnlyNVGPUModule method. + UsesOnlyNVGPUModuleFunc func() (bool, string) + + // calls tracks calls to the methods. + calls struct { + // HasDXCore holds details about calls to the HasDXCore method. + HasDXCore []struct { + } + // HasNvml holds details about calls to the HasNvml method. + HasNvml []struct { + } + // HasOnlyIntegratedGPUs holds details about calls to the HasOnlyIntegratedGPUs method. + HasOnlyIntegratedGPUs []struct { + } + // HasTegraFiles holds details about calls to the HasTegraFiles method. + HasTegraFiles []struct { + } + // IsTegraSystem holds details about calls to the IsTegraSystem method. + IsTegraSystem []struct { + } + // UsesOnlyNVGPUModule holds details about calls to the UsesOnlyNVGPUModule method. + UsesOnlyNVGPUModule []struct { + } + } + lockHasDXCore sync.RWMutex + lockHasNvml sync.RWMutex + lockHasOnlyIntegratedGPUs sync.RWMutex + lockHasTegraFiles sync.RWMutex + lockIsTegraSystem sync.RWMutex + lockUsesOnlyNVGPUModule sync.RWMutex +} + +// HasDXCore calls HasDXCoreFunc. +func (mock *PropertyExtractorMock) HasDXCore() (bool, string) { + if mock.HasDXCoreFunc == nil { + panic("PropertyExtractorMock.HasDXCoreFunc: method is nil but PropertyExtractor.HasDXCore was just called") + } + callInfo := struct { + }{} + mock.lockHasDXCore.Lock() + mock.calls.HasDXCore = append(mock.calls.HasDXCore, callInfo) + mock.lockHasDXCore.Unlock() + return mock.HasDXCoreFunc() +} + +// HasDXCoreCalls gets all the calls that were made to HasDXCore. +// Check the length with: +// +// len(mockedPropertyExtractor.HasDXCoreCalls()) +func (mock *PropertyExtractorMock) HasDXCoreCalls() []struct { +} { + var calls []struct { + } + mock.lockHasDXCore.RLock() + calls = mock.calls.HasDXCore + mock.lockHasDXCore.RUnlock() + return calls +} + +// HasNvml calls HasNvmlFunc. +func (mock *PropertyExtractorMock) HasNvml() (bool, string) { + if mock.HasNvmlFunc == nil { + panic("PropertyExtractorMock.HasNvmlFunc: method is nil but PropertyExtractor.HasNvml was just called") + } + callInfo := struct { + }{} + mock.lockHasNvml.Lock() + mock.calls.HasNvml = append(mock.calls.HasNvml, callInfo) + mock.lockHasNvml.Unlock() + return mock.HasNvmlFunc() +} + +// HasNvmlCalls gets all the calls that were made to HasNvml. +// Check the length with: +// +// len(mockedPropertyExtractor.HasNvmlCalls()) +func (mock *PropertyExtractorMock) HasNvmlCalls() []struct { +} { + var calls []struct { + } + mock.lockHasNvml.RLock() + calls = mock.calls.HasNvml + mock.lockHasNvml.RUnlock() + return calls +} + +// HasOnlyIntegratedGPUs calls HasOnlyIntegratedGPUsFunc. +func (mock *PropertyExtractorMock) HasOnlyIntegratedGPUs() (bool, string) { + if mock.HasOnlyIntegratedGPUsFunc == nil { + panic("PropertyExtractorMock.HasOnlyIntegratedGPUsFunc: method is nil but PropertyExtractor.HasOnlyIntegratedGPUs was just called") + } + callInfo := struct { + }{} + mock.lockHasOnlyIntegratedGPUs.Lock() + mock.calls.HasOnlyIntegratedGPUs = append(mock.calls.HasOnlyIntegratedGPUs, callInfo) + mock.lockHasOnlyIntegratedGPUs.Unlock() + return mock.HasOnlyIntegratedGPUsFunc() +} + +// HasOnlyIntegratedGPUsCalls gets all the calls that were made to HasOnlyIntegratedGPUs. +// Check the length with: +// +// len(mockedPropertyExtractor.HasOnlyIntegratedGPUsCalls()) +func (mock *PropertyExtractorMock) HasOnlyIntegratedGPUsCalls() []struct { +} { + var calls []struct { + } + mock.lockHasOnlyIntegratedGPUs.RLock() + calls = mock.calls.HasOnlyIntegratedGPUs + mock.lockHasOnlyIntegratedGPUs.RUnlock() + return calls +} + +// HasTegraFiles calls HasTegraFilesFunc. +func (mock *PropertyExtractorMock) HasTegraFiles() (bool, string) { + if mock.HasTegraFilesFunc == nil { + panic("PropertyExtractorMock.HasTegraFilesFunc: method is nil but PropertyExtractor.HasTegraFiles was just called") + } + callInfo := struct { + }{} + mock.lockHasTegraFiles.Lock() + mock.calls.HasTegraFiles = append(mock.calls.HasTegraFiles, callInfo) + mock.lockHasTegraFiles.Unlock() + return mock.HasTegraFilesFunc() +} + +// HasTegraFilesCalls gets all the calls that were made to HasTegraFiles. +// Check the length with: +// +// len(mockedPropertyExtractor.HasTegraFilesCalls()) +func (mock *PropertyExtractorMock) HasTegraFilesCalls() []struct { +} { + var calls []struct { + } + mock.lockHasTegraFiles.RLock() + calls = mock.calls.HasTegraFiles + mock.lockHasTegraFiles.RUnlock() + return calls +} + +// IsTegraSystem calls IsTegraSystemFunc. +func (mock *PropertyExtractorMock) IsTegraSystem() (bool, string) { + if mock.IsTegraSystemFunc == nil { + panic("PropertyExtractorMock.IsTegraSystemFunc: method is nil but PropertyExtractor.IsTegraSystem was just called") + } + callInfo := struct { + }{} + mock.lockIsTegraSystem.Lock() + mock.calls.IsTegraSystem = append(mock.calls.IsTegraSystem, callInfo) + mock.lockIsTegraSystem.Unlock() + return mock.IsTegraSystemFunc() +} + +// IsTegraSystemCalls gets all the calls that were made to IsTegraSystem. +// Check the length with: +// +// len(mockedPropertyExtractor.IsTegraSystemCalls()) +func (mock *PropertyExtractorMock) IsTegraSystemCalls() []struct { +} { + var calls []struct { + } + mock.lockIsTegraSystem.RLock() + calls = mock.calls.IsTegraSystem + mock.lockIsTegraSystem.RUnlock() + return calls +} + +// UsesOnlyNVGPUModule calls UsesOnlyNVGPUModuleFunc. +func (mock *PropertyExtractorMock) UsesOnlyNVGPUModule() (bool, string) { + if mock.UsesOnlyNVGPUModuleFunc == nil { + panic("PropertyExtractorMock.UsesOnlyNVGPUModuleFunc: method is nil but PropertyExtractor.UsesOnlyNVGPUModule was just called") + } + callInfo := struct { + }{} + mock.lockUsesOnlyNVGPUModule.Lock() + mock.calls.UsesOnlyNVGPUModule = append(mock.calls.UsesOnlyNVGPUModule, callInfo) + mock.lockUsesOnlyNVGPUModule.Unlock() + return mock.UsesOnlyNVGPUModuleFunc() +} + +// UsesOnlyNVGPUModuleCalls gets all the calls that were made to UsesOnlyNVGPUModule. +// Check the length with: +// +// len(mockedPropertyExtractor.UsesOnlyNVGPUModuleCalls()) +func (mock *PropertyExtractorMock) UsesOnlyNVGPUModuleCalls() []struct { +} { + var calls []struct { + } + mock.lockUsesOnlyNVGPUModule.RLock() + calls = mock.calls.UsesOnlyNVGPUModule + mock.lockUsesOnlyNVGPUModule.RUnlock() + return calls +} diff --git a/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/resolver.go b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/resolver.go new file mode 100644 index 00000000..0454d8a6 --- /dev/null +++ b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/resolver.go @@ -0,0 +1,64 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package info + +// Platform represents a supported plaform. +type Platform string + +const ( + PlatformAuto = Platform("auto") + PlatformNVML = Platform("nvml") + PlatformTegra = Platform("tegra") + PlatformWSL = Platform("wsl") + PlatformUnknown = Platform("unknown") +) + +type platformResolver struct { + logger basicLogger + platform Platform + propertyExtractor PropertyExtractor +} + +func (p platformResolver) ResolvePlatform() Platform { + if p.platform != PlatformAuto { + p.logger.Infof("Using requested platform '%s'", p.platform) + return p.platform + } + + hasDXCore, reason := p.propertyExtractor.HasDXCore() + p.logger.Debugf("Is WSL-based system? %v: %v", hasDXCore, reason) + + hasTegraFiles, reason := p.propertyExtractor.HasTegraFiles() + p.logger.Debugf("Is Tegra-based system? %v: %v", hasTegraFiles, reason) + + hasNVML, reason := p.propertyExtractor.HasNvml() + p.logger.Debugf("Is NVML-based system? %v: %v", hasNVML, reason) + + hasOnlyIntegratedGPUs, reason := p.propertyExtractor.HasOnlyIntegratedGPUs() + p.logger.Debugf("Has only integrated GPUs? %v: %v", hasOnlyIntegratedGPUs, reason) + + switch { + case hasDXCore: + return PlatformWSL + case (hasTegraFiles && !hasNVML), hasOnlyIntegratedGPUs: + return PlatformTegra + case hasNVML: + return PlatformNVML + default: + return PlatformUnknown + } +} diff --git a/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/root.go b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/root.go new file mode 100644 index 00000000..d38dc735 --- /dev/null +++ b/vendor/github.com/NVIDIA/go-nvlib/pkg/nvlib/info/root.go @@ -0,0 +1,86 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package info + +import ( + "fmt" + "path/filepath" + + "github.com/NVIDIA/go-nvml/pkg/dl" +) + +// root represents a directory on the filesystem relative to which libraries +// such as the NVIDIA driver libraries can be found. +type root string + +func (r root) join(parts ...string) string { + return filepath.Join(append([]string{string(r)}, parts...)...) +} + +// assertHasLibrary returns an error if the specified library cannot be loaded. +func (r root) assertHasLibrary(libraryName string) error { + const ( + libraryLoadFlags = dl.RTLD_LAZY + ) + lib := dl.New(r.tryResolveLibrary(libraryName), libraryLoadFlags) + if err := lib.Open(); err != nil { + return err + } + defer lib.Close() + + return nil +} + +// tryResolveLibrary attempts to locate the specified library in the root. +// If the root is not specified, is "/", or the library cannot be found in the +// set of predefined paths, the input is returned as is. +func (r root) tryResolveLibrary(libraryName string) string { + if r == "" || r == "/" { + return libraryName + } + + librarySearchPaths := []string{ + "/usr/lib64", + "/usr/lib/x86_64-linux-gnu", + "/usr/lib/aarch64-linux-gnu", + "/lib64", + "/lib/x86_64-linux-gnu", + "/lib/aarch64-linux-gnu", + } + + for _, d := range librarySearchPaths { + l := r.join(d, libraryName) + resolved, err := resolveLink(l) + if err != nil { + continue + } + return resolved + } + + return libraryName +} + +// resolveLink finds the target of a symlink or the file itself in the +// case of a regular file. +// This is equivalent to running `readlink -f ${l}`. +func resolveLink(l string) (string, error) { + resolved, err := filepath.EvalSymlinks(l) + if err != nil { + return "", fmt.Errorf("error resolving link '%v': %w", l, err) + } + return resolved, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/LICENSE b/vendor/github.com/NVIDIA/nvidia-container-toolkit/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor 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, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/builder.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/builder.go new file mode 100644 index 00000000..a9cc61ee --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/builder.go @@ -0,0 +1,170 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package image + +import ( + "fmt" + "strings" + + "github.com/opencontainers/runtime-spec/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +type builder struct { + CUDA + + disableRequire bool +} + +// Option is a functional option for creating a CUDA image. +type Option func(*builder) error + +// New creates a new CUDA image from the input options. +func New(opt ...Option) (CUDA, error) { + b := &builder{ + CUDA: CUDA{ + acceptEnvvarUnprivileged: true, + }, + } + for _, o := range opt { + if err := o(b); err != nil { + return CUDA{}, err + } + } + + if b.logger == nil { + b.logger = logger.New() + } + if b.env == nil { + b.env = make(map[string]string) + } + + return b.build() +} + +// build creates a CUDA image from the builder. +func (b builder) build() (CUDA, error) { + if b.disableRequire { + b.env[EnvVarNvidiaDisableRequire] = "true" + } + + return b.CUDA, nil +} + +func WithAcceptDeviceListAsVolumeMounts(acceptDeviceListAsVolumeMounts bool) Option { + return func(b *builder) error { + b.acceptDeviceListAsVolumeMounts = acceptDeviceListAsVolumeMounts + return nil + } +} + +func WithAcceptEnvvarUnprivileged(acceptEnvvarUnprivileged bool) Option { + return func(b *builder) error { + b.acceptEnvvarUnprivileged = acceptEnvvarUnprivileged + return nil + } +} + +func WithAnnotations(annotations map[string]string) Option { + return func(b *builder) error { + b.annotations = annotations + return nil + } +} + +func WithAnnotationsPrefixes(annotationsPrefixes []string) Option { + return func(b *builder) error { + b.annotationsPrefixes = annotationsPrefixes + return nil + } +} + +// WithDisableRequire sets the disable require option. +func WithDisableRequire(disableRequire bool) Option { + return func(b *builder) error { + b.disableRequire = disableRequire + return nil + } +} + +// WithEnv sets the environment variables to use when creating the CUDA image. +// Note that this also overwrites the values set with WithEnvMap. +func WithEnv(env []string) Option { + return func(b *builder) error { + envmap := make(map[string]string) + for _, e := range env { + parts := strings.SplitN(e, "=", 2) + if len(parts) != 2 { + return fmt.Errorf("invalid environment variable: %v", e) + } + envmap[parts[0]] = parts[1] + } + return WithEnvMap(envmap)(b) + } +} + +// WithEnvMap sets the environment variable map to use when creating the CUDA image. +// Note that this also overwrites the values set with WithEnv. +func WithEnvMap(env map[string]string) Option { + return func(b *builder) error { + b.env = env + return nil + } +} + +// WithIgnoreImexChannelRequests sets whether per-container IMEX channel +// requests are supported. +func WithIgnoreImexChannelRequests(ignoreImexChannelRequests bool) Option { + return func(b *builder) error { + b.ignoreImexChannelRequests = ignoreImexChannelRequests + return nil + } +} + +// WithLogger sets the logger to use when creating the CUDA image. +func WithLogger(logger logger.Interface) Option { + return func(b *builder) error { + b.logger = logger + return nil + } +} + +// WithMounts sets the mounts associated with the CUDA image. +func WithMounts(mounts []specs.Mount) Option { + return func(b *builder) error { + b.mounts = mounts + return nil + } +} + +// WithPreferredVisibleDevicesEnvVars sets the environment variables that +// should take precedence over the default NVIDIA_VISIBLE_DEVICES. +func WithPreferredVisibleDevicesEnvVars(preferredVisibleDeviceEnvVars ...string) Option { + return func(b *builder) error { + b.preferredVisibleDeviceEnvVars = preferredVisibleDeviceEnvVars + return nil + } +} + +// WithPrivileged sets whether an image is privileged or not. +func WithPrivileged(isPrivileged bool) Option { + return func(b *builder) error { + b.isPrivileged = isPrivileged + return nil + } +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/capabilities.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/capabilities.go new file mode 100644 index 00000000..824a6db9 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/capabilities.go @@ -0,0 +1,146 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package image + +import ( + "sort" + "strings" +) + +// DriverCapability represents the possible values of NVIDIA_DRIVER_CAPABILITIES +type DriverCapability string + +// Constants for the supported driver capabilities +const ( + DriverCapabilityAll DriverCapability = "all" + DriverCapabilityNone DriverCapability = "none" + DriverCapabilityCompat32 DriverCapability = "compat32" + DriverCapabilityCompute DriverCapability = "compute" + DriverCapabilityDisplay DriverCapability = "display" + DriverCapabilityGraphics DriverCapability = "graphics" + DriverCapabilityNgx DriverCapability = "ngx" + DriverCapabilityUtility DriverCapability = "utility" + DriverCapabilityVideo DriverCapability = "video" +) + +var ( + driverCapabilitiesNone = NewDriverCapabilities() + driverCapabilitiesAll = NewDriverCapabilities("all") + + // DefaultDriverCapabilities sets the value for driver capabilities if no value is set. + DefaultDriverCapabilities = NewDriverCapabilities("utility,compute") + // SupportedDriverCapabilities defines the set of all supported driver capabilities. + SupportedDriverCapabilities = NewDriverCapabilities("compute,compat32,graphics,utility,video,display,ngx") +) + +// NewDriverCapabilities creates a set of driver capabilities from the specified capabilities +func NewDriverCapabilities(capabilities ...string) DriverCapabilities { + dc := make(DriverCapabilities) + for _, capability := range capabilities { + for _, c := range strings.Split(capability, ",") { + trimmed := strings.TrimSpace(c) + if trimmed == "" { + continue + } + dc[DriverCapability(trimmed)] = true + } + } + return dc +} + +// DriverCapabilities represents the NVIDIA_DRIVER_CAPABILITIES set for the specified image. +type DriverCapabilities map[DriverCapability]bool + +// Has check whether the specified capability is selected. +func (c DriverCapabilities) Has(capability DriverCapability) bool { + if c.IsAll() { + return true + } + return c[capability] +} + +// Any checks whether any of the specified capabilities are set +func (c DriverCapabilities) Any(capabilities ...DriverCapability) bool { + if c.IsAll() { + return true + } + for _, cap := range capabilities { + if c.Has(cap) { + return true + } + } + return false +} + +// List returns the list of driver capabilities. +// The list is sorted. +func (c DriverCapabilities) List() []string { + var capabilities []string + for capability := range c { + capabilities = append(capabilities, string(capability)) + } + sort.Strings(capabilities) + return capabilities +} + +// String returns the string repesentation of the driver capabilities. +func (c DriverCapabilities) String() string { + if c.IsAll() { + return "all" + } + return strings.Join(c.List(), ",") +} + +// IsAll indicates whether the set of capabilities is `all` +func (c DriverCapabilities) IsAll() bool { + return c[DriverCapabilityAll] +} + +// Intersection returns a new set which includes the item in BOTH d and s2. +// For example: d = {a1, a2} s2 = {a2, a3} s1.Intersection(s2) = {a2} +func (c DriverCapabilities) Intersection(s2 DriverCapabilities) DriverCapabilities { + if s2.IsAll() { + return c + } + if c.IsAll() { + return s2 + } + + intersection := make(DriverCapabilities) + for capability := range s2 { + if c[capability] { + intersection[capability] = true + } + } + + return intersection +} + +// IsSuperset returns true if and only if d is a superset of s2. +func (c DriverCapabilities) IsSuperset(s2 DriverCapabilities) bool { + if c.IsAll() { + return true + } + + for capability := range s2 { + if !c[capability] { + return false + } + } + + return true +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/cuda_image.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/cuda_image.go new file mode 100644 index 00000000..09f73e82 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/cuda_image.go @@ -0,0 +1,469 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package image + +import ( + "fmt" + "path/filepath" + "slices" + "strconv" + "strings" + + "github.com/opencontainers/runtime-spec/specs-go" + "golang.org/x/mod/semver" + "tags.cncf.io/container-device-interface/pkg/parser" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +const ( + DeviceListAsVolumeMountsRoot = "/var/run/nvidia-container-devices" + + volumeMountDevicePrefixCDI = "cdi/" + volumeMountDevicePrefixImex = "imex/" +) + +// CUDA represents a CUDA image that can be used for GPU computing. This wraps +// a map of environment variable to values that can be used to perform lookups +// such as requirements. +type CUDA struct { + logger logger.Interface + + annotations map[string]string + env map[string]string + isPrivileged bool + mounts []specs.Mount + + annotationsPrefixes []string + acceptDeviceListAsVolumeMounts bool + acceptEnvvarUnprivileged bool + ignoreImexChannelRequests bool + preferredVisibleDeviceEnvVars []string +} + +// NewCUDAImageFromSpec creates a CUDA image from the input OCI runtime spec. +// The process environment is read (if present) to construc the CUDA Image. +func NewCUDAImageFromSpec(spec *specs.Spec, opts ...Option) (CUDA, error) { + if spec == nil { + return New(opts...) + } + + var env []string + if spec.Process != nil { + env = spec.Process.Env + } + + specOpts := []Option{ + WithAnnotations(spec.Annotations), + WithEnv(env), + WithMounts(spec.Mounts), + WithPrivileged(IsPrivileged((*OCISpec)(spec))), + } + + return New(append(opts, specOpts...)...) +} + +// newCUDAImageFromEnv creates a CUDA image from the input environment. The environment +// is a list of strings of the form ENVAR=VALUE. +func newCUDAImageFromEnv(env []string) (CUDA, error) { + return New(WithEnv(env)) +} + +// Getenv returns the value of the specified environment variable. +// If the environment variable is not specified, an empty string is returned. +func (i CUDA) Getenv(key string) string { + return i.env[key] +} + +// HasEnvvar checks whether the specified envvar is defined in the image. +func (i CUDA) HasEnvvar(key string) bool { + _, exists := i.env[key] + return exists +} + +// IsLegacy returns whether the associated CUDA image is a "legacy" image. An +// image is considered legacy if it has a CUDA_VERSION environment variable defined +// and no NVIDIA_REQUIRE_CUDA environment variable defined. +func (i CUDA) IsLegacy() bool { + legacyCudaVersion := i.env[EnvVarCudaVersion] + cudaRequire := i.env[EnvVarNvidiaRequireCuda] + return len(legacyCudaVersion) > 0 && len(cudaRequire) == 0 +} + +func (i CUDA) IsPrivileged() bool { + return i.isPrivileged +} + +// GetRequirements returns the requirements from all NVIDIA_REQUIRE_ environment +// variables. +func (i CUDA) GetRequirements() ([]string, error) { + if i.HasDisableRequire() { + return nil, nil + } + + // All variables with the "NVIDIA_REQUIRE_" prefix are passed to nvidia-container-cli + var requirements []string + for name, value := range i.env { + if strings.HasPrefix(name, NvidiaRequirePrefix) && !strings.HasPrefix(name, EnvVarNvidiaRequireJetpack) { + requirements = append(requirements, value) + } + } + if i.IsLegacy() { + v, err := i.legacyVersion() + if err != nil { + return nil, fmt.Errorf("failed to get version: %v", err) + } + cudaRequire := fmt.Sprintf("cuda>=%s", v) + requirements = append(requirements, cudaRequire) + } + return requirements, nil +} + +// HasDisableRequire checks for the value of the NVIDIA_DISABLE_REQUIRE. If set +// to a valid (true) boolean value this can be used to disable the requirement checks +func (i CUDA) HasDisableRequire() bool { + if disable, exists := i.env[EnvVarNvidiaDisableRequire]; exists { + // i.logger.Debugf("NVIDIA_DISABLE_REQUIRE=%v; skipping requirement checks", disable) + d, _ := strconv.ParseBool(disable) + return d + } + + return false +} + +// devicesFromEnvvars returns the devices requested by the image through environment variables +func (i CUDA) devicesFromEnvvars(envVars ...string) []string { + // We concantenate all the devices from the specified env. + var isSet bool + var devices []string + requested := make(map[string]bool) + for _, envVar := range envVars { + if devs, ok := i.env[envVar]; ok { + isSet = true + for _, d := range strings.Split(devs, ",") { + trimmed := strings.TrimSpace(d) + if len(trimmed) == 0 { + continue + } + devices = append(devices, trimmed) + requested[trimmed] = true + } + } + } + + // Environment variable unset with legacy image: default to "all". + if !isSet && len(devices) == 0 && i.IsLegacy() { + devices = []string{"all"} + } + + // Environment variable unset or empty or "void": return nil + if len(devices) == 0 || requested["void"] { + devices = []string{"void"} + } + + return NewVisibleDevices(devices...).List() +} + +// GetDriverCapabilities returns the requested driver capabilities. +func (i CUDA) GetDriverCapabilities() DriverCapabilities { + env := i.env[EnvVarNvidiaDriverCapabilities] + + capabilities := make(DriverCapabilities) + for _, c := range strings.Split(env, ",") { + capabilities[DriverCapability(c)] = true + } + + return capabilities +} + +func (i CUDA) legacyVersion() (string, error) { + cudaVersion := i.env[EnvVarCudaVersion] + majorMinor, err := parseMajorMinorVersion(cudaVersion) + if err != nil { + return "", fmt.Errorf("invalid CUDA version %v: %v", cudaVersion, err) + } + + return majorMinor, nil +} + +func parseMajorMinorVersion(version string) (string, error) { + vVersion := "v" + strings.TrimPrefix(version, "v") + + if !semver.IsValid(vVersion) { + return "", fmt.Errorf("invalid version string") + } + + majorMinor := strings.TrimPrefix(semver.MajorMinor(vVersion), "v") + parts := strings.Split(majorMinor, ".") + + var err error + _, err = strconv.ParseUint(parts[0], 10, 32) + if err != nil { + return "", fmt.Errorf("invalid major version") + } + _, err = strconv.ParseUint(parts[1], 10, 32) + if err != nil { + return "", fmt.Errorf("invalid minor version") + } + return majorMinor, nil +} + +// OnlyFullyQualifiedCDIDevices returns true if all devices requested in the image are requested as CDI devices/ +func (i CUDA) OnlyFullyQualifiedCDIDevices() bool { + var hasCDIdevice bool + for _, device := range i.VisibleDevices() { + if !parser.IsQualifiedName(device) { + return false + } + hasCDIdevice = true + } + return hasCDIdevice +} + +// visibleEnvVars returns the environment variables that are used to determine device visibility. +// It returns the preferred environment variables that are set, or NVIDIA_VISIBLE_DEVICES if none are set. +func (i CUDA) visibleEnvVars() []string { + var envVars []string + for _, envVar := range i.preferredVisibleDeviceEnvVars { + if !i.HasEnvvar(envVar) { + continue + } + envVars = append(envVars, envVar) + } + if len(envVars) > 0 { + return envVars + } + return []string{EnvVarNvidiaVisibleDevices} +} + +// VisibleDevices returns a list of devices requested in the container image. +// If volume mount requests are enabled these are returned if requested, +// otherwise device requests through environment variables are considered. +// In cases where environment variable requests required privileged containers, +// such devices requests are ignored. +func (i CUDA) VisibleDevices() []string { + // If annotation device requests are present, these are preferred. + annotationDeviceRequests := i.cdiDeviceRequestsFromAnnotations() + if len(annotationDeviceRequests) > 0 { + return annotationDeviceRequests + } + + // If enabled, try and get the device list from volume mounts first + if i.acceptDeviceListAsVolumeMounts { + volumeMountDeviceRequests := i.visibleDevicesFromMounts() + if len(volumeMountDeviceRequests) > 0 { + return volumeMountDeviceRequests + } + } + + // Get the Fallback to reading from the environment variable if privileges are correct + envVarDeviceRequests := i.visibleDevicesFromEnvVar() + if len(envVarDeviceRequests) == 0 { + return nil + } + + // If the container is privileged, or environment variable requests are + // allowed for unprivileged containers, these devices are returned. + if i.isPrivileged || i.acceptEnvvarUnprivileged { + return envVarDeviceRequests + } + + // We log a warning if we are ignoring the environment variable requests. + envVars := i.visibleEnvVars() + if len(envVars) > 0 { + i.logger.Warningf("Ignoring devices requested by environment variable(s) in unprivileged container: %v", envVars) + } + + return nil +} + +// cdiDeviceRequestsFromAnnotations returns a list of devices specified in the +// annotations. +// Keys starting with the specified prefixes are considered and expected to +// contain a comma-separated list of fully-qualified CDI devices names. +// The format of the requested devices is not checked and the list is not +// deduplicated. +func (i CUDA) cdiDeviceRequestsFromAnnotations() []string { + if len(i.annotationsPrefixes) == 0 || len(i.annotations) == 0 { + return nil + } + + var annotationKeys []string + for key := range i.annotations { + for _, prefix := range i.annotationsPrefixes { + if strings.HasPrefix(key, prefix) { + annotationKeys = append(annotationKeys, key) + // There is no need to check additional prefixes since we + // typically deduplicate devices in any case. + break + } + } + } + // We sort the annotationKeys for consistent results. + slices.Sort(annotationKeys) + + var devices []string + for _, key := range annotationKeys { + devices = append(devices, strings.Split(i.annotations[key], ",")...) + } + return devices +} + +// visibleDevicesFromEnvVar returns the set of visible devices requested through environment variables. +// If any of the preferredVisibleDeviceEnvVars are present in the image, they +// are used to determine the visible devices. If this is not the case, the +// NVIDIA_VISIBLE_DEVICES environment variable is used. +func (i CUDA) visibleDevicesFromEnvVar() []string { + envVars := i.visibleEnvVars() + return i.devicesFromEnvvars(envVars...) +} + +// visibleDevicesFromMounts returns the set of visible devices requested as mounts. +func (i CUDA) visibleDevicesFromMounts() []string { + var devices []string + for _, device := range i.requestsFromMounts() { + switch { + case strings.HasPrefix(device, volumeMountDevicePrefixImex): + continue + case strings.HasPrefix(device, volumeMountDevicePrefixCDI): + name, err := cdiDeviceMountRequest(device).qualifiedName() + if err != nil { + i.logger.Warningf("Ignoring invalid mount request for CDI device %v: %v", device, err) + continue + } + devices = append(devices, name) + default: + devices = append(devices, device) + } + + } + return devices +} + +// requestsFromMounts returns a list of device specified as mounts. +func (i CUDA) requestsFromMounts() []string { + root := filepath.Clean(DeviceListAsVolumeMountsRoot) + seen := make(map[string]bool) + var devices []string + for _, m := range i.mounts { + source := filepath.Clean(m.Source) + // Only consider mounts who's host volume is /dev/null + if source != "/dev/null" { + continue + } + + destination := filepath.Clean(m.Destination) + if seen[destination] { + continue + } + seen[destination] = true + + // Only consider container mount points that begin with 'root' + if !strings.HasPrefix(destination, root) { + continue + } + + // Grab the full path beyond 'root' and add it to the list of devices + device := strings.Trim(strings.TrimPrefix(destination, root), "/") + if len(device) == 0 { + continue + } + devices = append(devices, device) + } + return devices +} + +// a cdiDeviceMountRequest represents a CDI device requests as a mount. +// Here the host path /dev/null is mounted to a particular path in the container. +// The container path has the form: +// /var/run/nvidia-container-devices/cdi/// +// or +// /var/run/nvidia-container-devices/cdi//= +type cdiDeviceMountRequest string + +// qualifiedName returns the fully-qualified name of the CDI device. +func (m cdiDeviceMountRequest) qualifiedName() (string, error) { + if !strings.HasPrefix(string(m), volumeMountDevicePrefixCDI) { + return "", fmt.Errorf("invalid mount CDI device request: %s", m) + } + + requestedDevice := strings.TrimPrefix(string(m), volumeMountDevicePrefixCDI) + if parser.IsQualifiedName(requestedDevice) { + return requestedDevice, nil + } + + parts := strings.SplitN(requestedDevice, "/", 3) + if len(parts) != 3 { + return "", fmt.Errorf("invalid mount CDI device request: %s", m) + } + return fmt.Sprintf("%s/%s=%s", parts[0], parts[1], parts[2]), nil +} + +func (i CUDA) ImexChannelRequests() []string { + if i.ignoreImexChannelRequests { + return nil + } + + // If enabled, try and get the device list from volume mounts first + if i.acceptDeviceListAsVolumeMounts { + volumeMountDeviceRequests := i.imexChannelsFromMounts() + if len(volumeMountDeviceRequests) > 0 { + return volumeMountDeviceRequests + } + } + + // Get the Fallback to reading from the environment variable if privileges are correct + envVarDeviceRequests := i.imexChannelsFromEnvVar() + if len(envVarDeviceRequests) == 0 { + return nil + } + + // If the container is privileged, or environment variable requests are + // allowed for unprivileged containers, these devices are returned. + if i.isPrivileged || i.acceptEnvvarUnprivileged { + return envVarDeviceRequests + } + + // We log a warning if we are ignoring the environment variable requests. + envVars := []string{EnvVarNvidiaImexChannels} + if len(envVars) > 0 { + i.logger.Warningf("Ignoring request by environment variable(s) in unprivileged container: %v", envVars) + } + + return nil +} + +// imexChannelsFromEnvVar returns the list of IMEX channels requested for the image. +func (i CUDA) imexChannelsFromEnvVar() []string { + imexChannels := i.devicesFromEnvvars(EnvVarNvidiaImexChannels) + if len(imexChannels) == 1 && imexChannels[0] == "all" { + return nil + } + return imexChannels +} + +// imexChannelsFromMounts returns the list of IMEX channels requested for the image. +func (i CUDA) imexChannelsFromMounts() []string { + var channels []string + for _, mountDevice := range i.requestsFromMounts() { + if !strings.HasPrefix(mountDevice, volumeMountDevicePrefixImex) { + continue + } + channels = append(channels, strings.TrimPrefix(mountDevice, volumeMountDevicePrefixImex)) + } + return channels +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/devices.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/devices.go new file mode 100644 index 00000000..f5a6ad95 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/devices.go @@ -0,0 +1,127 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package image + +import ( + "strings" +) + +// VisibleDevices represents the devices selected in a container image +// through the NVIDIA_VISIBLE_DEVICES or other environment variables +type VisibleDevices interface { + List() []string + Has(string) bool +} + +var _ VisibleDevices = (*all)(nil) +var _ VisibleDevices = (*none)(nil) +var _ VisibleDevices = (*void)(nil) +var _ VisibleDevices = (*devices)(nil) + +// NewVisibleDevices creates a VisibleDevices based on the value of the specified envvar. +func NewVisibleDevices(envvars ...string) VisibleDevices { + for _, envvar := range envvars { + if envvar == "all" { + return all{} + } + if envvar == "none" { + return none{} + } + if envvar == "" || envvar == "void" { + return void{} + } + } + + return newDevices(envvars...) +} + +type all struct{} + +// List returns ["all"] for all devices +func (a all) List() []string { + return []string{"all"} +} + +// Has for all devices is true for any id except the empty ID +func (a all) Has(id string) bool { + return id != "" +} + +type none struct{} + +// List returns [""] for the none devices +func (n none) List() []string { + return []string{""} +} + +// Has for none devices is false for any id +func (n none) Has(id string) bool { + return false +} + +type void struct { + none +} + +// List returns nil for the void devices +func (v void) List() []string { + return nil +} + +type devices struct { + len int + lookup map[string]int +} + +func newDevices(idOrCommaSeparated ...string) devices { + lookup := make(map[string]int) + + i := 0 + for _, commaSeparated := range idOrCommaSeparated { + for _, id := range strings.Split(commaSeparated, ",") { + lookup[id] = i + i++ + } + } + + d := devices{ + len: i, + lookup: lookup, + } + return d +} + +// List returns the list of requested devices +func (d devices) List() []string { + list := make([]string, d.len) + + for id, i := range d.lookup { + list[i] = id + } + + return list +} + +// Has checks whether the specified ID is in the set of requested devices +func (d devices) Has(id string) bool { + if id == "" { + return false + } + + _, exist := d.lookup[id] + return exist +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/envvars.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/envvars.go new file mode 100644 index 00000000..0789f22f --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/envvars.go @@ -0,0 +1,31 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package image + +const ( + EnvVarCudaVersion = "CUDA_VERSION" + EnvVarNvidiaDisableRequire = "NVIDIA_DISABLE_REQUIRE" + EnvVarNvidiaDriverCapabilities = "NVIDIA_DRIVER_CAPABILITIES" + EnvVarNvidiaImexChannels = "NVIDIA_IMEX_CHANNELS" + EnvVarNvidiaMigConfigDevices = "NVIDIA_MIG_CONFIG_DEVICES" + EnvVarNvidiaMigMonitorDevices = "NVIDIA_MIG_MONITOR_DEVICES" + EnvVarNvidiaRequireCuda = NvidiaRequirePrefix + "CUDA" + EnvVarNvidiaRequireJetpack = NvidiaRequirePrefix + "JETPACK" + EnvVarNvidiaVisibleDevices = "NVIDIA_VISIBLE_DEVICES" + + NvidiaRequirePrefix = "NVIDIA_REQUIRE_" +) diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/privileged.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/privileged.go new file mode 100644 index 00000000..04f32cf5 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/config/image/privileged.go @@ -0,0 +1,62 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package image + +import ( + "github.com/opencontainers/runtime-spec/specs-go" +) + +const ( + capSysAdmin = "CAP_SYS_ADMIN" +) + +type CapabilitiesGetter interface { + GetCapabilities() []string +} + +type OCISpec specs.Spec + +type OCISpecCapabilities specs.LinuxCapabilities + +// IsPrivileged returns true if the container is a privileged container. +func IsPrivileged(s CapabilitiesGetter) bool { + if s == nil { + return false + } + for _, c := range s.GetCapabilities() { + if c == capSysAdmin { + return true + } + } + + return false +} + +func (s OCISpec) GetCapabilities() []string { + if s.Process == nil || s.Process.Capabilities == nil { + return nil + } + return (*OCISpecCapabilities)(s.Process.Capabilities).GetCapabilities() +} + +func (c OCISpecCapabilities) GetCapabilities() []string { + // We only make sure that the bounding capability set has + // CAP_SYS_ADMIN. This allows us to make sure that the container was + // actually started as '--privileged', but also allow non-root users to + // access the privileged NVIDIA capabilities. + return c.Bounding +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/cache.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/cache.go new file mode 100644 index 00000000..56523386 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/cache.go @@ -0,0 +1,95 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import "sync" + +type cache struct { + d Discover + + sync.Mutex + devices []Device + envVars []EnvVar + hooks []Hook + mounts []Mount +} + +var _ Discover = (*cache)(nil) + +// WithCache decorates the specified disoverer with a cache. +func WithCache(d Discover) Discover { + if d == nil { + return None{} + } + return &cache{d: d} +} + +func (c *cache) Devices() ([]Device, error) { + c.Lock() + defer c.Unlock() + + if c.devices == nil { + devices, err := c.d.Devices() + if err != nil { + return nil, err + } + c.devices = devices + } + return c.devices, nil +} + +func (c *cache) EnvVars() ([]EnvVar, error) { + c.Lock() + defer c.Unlock() + + if c.envVars == nil { + envVars, err := c.d.EnvVars() + if err != nil { + return nil, err + } + c.envVars = envVars + } + return c.envVars, nil +} + +func (c *cache) Hooks() ([]Hook, error) { + c.Lock() + defer c.Unlock() + + if c.hooks == nil { + hooks, err := c.d.Hooks() + if err != nil { + return nil, err + } + c.hooks = hooks + } + return c.hooks, nil +} + +func (c *cache) Mounts() ([]Mount, error) { + c.Lock() + defer c.Unlock() + + if c.mounts == nil { + mounts, err := c.d.Mounts() + if err != nil { + return nil, err + } + c.mounts = mounts + } + return c.mounts, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/char_devices.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/char_devices.go new file mode 100644 index 00000000..8d59430d --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/char_devices.go @@ -0,0 +1,62 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import ( + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" +) + +// charDevices is a discover for a list of character devices +type charDevices mounts + +var _ Discover = (*charDevices)(nil) + +// NewCharDeviceDiscoverer creates a discoverer which locates the specified set of device nodes. +func NewCharDeviceDiscoverer(logger logger.Interface, devRoot string, devices []string) Discover { + locator := lookup.NewCharDeviceLocator( + lookup.WithLogger(logger), + lookup.WithRoot(devRoot), + ) + + return (*charDevices)(newMounts(logger, locator, devRoot, devices)) +} + +// Mounts returns the discovered mounts for the charDevices. +// Since this explicitly specifies a device list, the mounts are nil. +func (d *charDevices) Mounts() ([]Mount, error) { + return nil, nil +} + +// Devices returns the discovered devices for the charDevices. +// Here the device nodes are first discovered as mounts and these are converted to devices. +func (d *charDevices) Devices() ([]Device, error) { + devicesAsMounts, err := (*mounts)(d).Mounts() + if err != nil { + return nil, err + } + var devices []Device + for _, mount := range devicesAsMounts { + device := Device{ + HostPath: mount.HostPath, + Path: mount.Path, + } + devices = append(devices, device) + } + + return devices, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/compat_libs.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/compat_libs.go new file mode 100644 index 00000000..71926a9f --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/compat_libs.go @@ -0,0 +1,18 @@ +package discover + +import ( + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +// NewCUDACompatHookDiscoverer creates a discoverer for a enable-cuda-compat hook. +// This hook is responsible for setting up CUDA compatibility in the container and depends on the host driver version. +func NewCUDACompatHookDiscoverer(logger logger.Interface, hookCreator HookCreator, version string) Discover { + var args []string + if version != "" && !strings.Contains(version, "*") { + args = append(args, "--host-driver-version="+version) + } + + return hookCreator.Create("enable-cuda-compat", args...) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/discover.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/discover.go new file mode 100644 index 00000000..8d51b59b --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/discover.go @@ -0,0 +1,54 @@ +/* +# Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package discover + +// Device represents a discovered character device. +type Device struct { + HostPath string + Path string +} + +// EnvVar represents a discovered environment variable. +type EnvVar struct { + Name string + Value string +} + +// Mount represents a discovered mount. +type Mount struct { + HostPath string + Path string + Options []string +} + +// Hook represents a discovered hook. +type Hook struct { + Lifecycle string + Path string + Args []string + Env []string +} + +// Discover defines an interface for discovering the devices, mounts, and hooks available on a system +// +//go:generate moq -rm -fmt=goimports -stub -out discover_mock.go . Discover +type Discover interface { + Devices() ([]Device, error) + EnvVars() ([]EnvVar, error) + Mounts() ([]Mount, error) + Hooks() ([]Hook, error) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/discover_mock.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/discover_mock.go new file mode 100644 index 00000000..2a66cf0e --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/discover_mock.go @@ -0,0 +1,194 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package discover + +import ( + "sync" +) + +// Ensure, that DiscoverMock does implement Discover. +// If this is not the case, regenerate this file with moq. +var _ Discover = &DiscoverMock{} + +// DiscoverMock is a mock implementation of Discover. +// +// func TestSomethingThatUsesDiscover(t *testing.T) { +// +// // make and configure a mocked Discover +// mockedDiscover := &DiscoverMock{ +// DevicesFunc: func() ([]Device, error) { +// panic("mock out the Devices method") +// }, +// EnvVarsFunc: func() ([]EnvVar, error) { +// panic("mock out the EnvVars method") +// }, +// HooksFunc: func() ([]Hook, error) { +// panic("mock out the Hooks method") +// }, +// MountsFunc: func() ([]Mount, error) { +// panic("mock out the Mounts method") +// }, +// } +// +// // use mockedDiscover in code that requires Discover +// // and then make assertions. +// +// } +type DiscoverMock struct { + // DevicesFunc mocks the Devices method. + DevicesFunc func() ([]Device, error) + + // EnvVarsFunc mocks the EnvVars method. + EnvVarsFunc func() ([]EnvVar, error) + + // HooksFunc mocks the Hooks method. + HooksFunc func() ([]Hook, error) + + // MountsFunc mocks the Mounts method. + MountsFunc func() ([]Mount, error) + + // calls tracks calls to the methods. + calls struct { + // Devices holds details about calls to the Devices method. + Devices []struct { + } + // EnvVars holds details about calls to the EnvVars method. + EnvVars []struct { + } + // Hooks holds details about calls to the Hooks method. + Hooks []struct { + } + // Mounts holds details about calls to the Mounts method. + Mounts []struct { + } + } + lockDevices sync.RWMutex + lockEnvVars sync.RWMutex + lockHooks sync.RWMutex + lockMounts sync.RWMutex +} + +// Devices calls DevicesFunc. +func (mock *DiscoverMock) Devices() ([]Device, error) { + callInfo := struct { + }{} + mock.lockDevices.Lock() + mock.calls.Devices = append(mock.calls.Devices, callInfo) + mock.lockDevices.Unlock() + if mock.DevicesFunc == nil { + var ( + devicesOut []Device + errOut error + ) + return devicesOut, errOut + } + return mock.DevicesFunc() +} + +// DevicesCalls gets all the calls that were made to Devices. +// Check the length with: +// +// len(mockedDiscover.DevicesCalls()) +func (mock *DiscoverMock) DevicesCalls() []struct { +} { + var calls []struct { + } + mock.lockDevices.RLock() + calls = mock.calls.Devices + mock.lockDevices.RUnlock() + return calls +} + +// EnvVars calls EnvVarsFunc. +func (mock *DiscoverMock) EnvVars() ([]EnvVar, error) { + callInfo := struct { + }{} + mock.lockEnvVars.Lock() + mock.calls.EnvVars = append(mock.calls.EnvVars, callInfo) + mock.lockEnvVars.Unlock() + if mock.EnvVarsFunc == nil { + var ( + envVarsOut []EnvVar + errOut error + ) + return envVarsOut, errOut + } + return mock.EnvVarsFunc() +} + +// EnvVarsCalls gets all the calls that were made to EnvVars. +// Check the length with: +// +// len(mockedDiscover.EnvVarsCalls()) +func (mock *DiscoverMock) EnvVarsCalls() []struct { +} { + var calls []struct { + } + mock.lockEnvVars.RLock() + calls = mock.calls.EnvVars + mock.lockEnvVars.RUnlock() + return calls +} + +// Hooks calls HooksFunc. +func (mock *DiscoverMock) Hooks() ([]Hook, error) { + callInfo := struct { + }{} + mock.lockHooks.Lock() + mock.calls.Hooks = append(mock.calls.Hooks, callInfo) + mock.lockHooks.Unlock() + if mock.HooksFunc == nil { + var ( + hooksOut []Hook + errOut error + ) + return hooksOut, errOut + } + return mock.HooksFunc() +} + +// HooksCalls gets all the calls that were made to Hooks. +// Check the length with: +// +// len(mockedDiscover.HooksCalls()) +func (mock *DiscoverMock) HooksCalls() []struct { +} { + var calls []struct { + } + mock.lockHooks.RLock() + calls = mock.calls.Hooks + mock.lockHooks.RUnlock() + return calls +} + +// Mounts calls MountsFunc. +func (mock *DiscoverMock) Mounts() ([]Mount, error) { + callInfo := struct { + }{} + mock.lockMounts.Lock() + mock.calls.Mounts = append(mock.calls.Mounts, callInfo) + mock.lockMounts.Unlock() + if mock.MountsFunc == nil { + var ( + mountsOut []Mount + errOut error + ) + return mountsOut, errOut + } + return mock.MountsFunc() +} + +// MountsCalls gets all the calls that were made to Mounts. +// Check the length with: +// +// len(mockedDiscover.MountsCalls()) +func (mock *DiscoverMock) MountsCalls() []struct { +} { + var calls []struct { + } + mock.lockMounts.RLock() + calls = mock.calls.Mounts + mock.lockMounts.RUnlock() + return calls +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/envvar.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/envvar.go new file mode 100644 index 00000000..3c84db0c --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/envvar.go @@ -0,0 +1,41 @@ +/** +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +var _ Discover = (*EnvVar)(nil) + +// Devices returns an empty list of devices for a EnvVar discoverer. +func (e EnvVar) Devices() ([]Device, error) { + return nil, nil +} + +// EnvVars returns an empty list of envs for a EnvVar discoverer. +func (e EnvVar) EnvVars() ([]EnvVar, error) { + return []EnvVar{e}, nil +} + +// Mounts returns an empty list of mounts for a EnvVar discoverer. +func (e EnvVar) Mounts() ([]Mount, error) { + return nil, nil +} + +// Hooks allows the Hook type to also implement the Discoverer interface. +// It returns a single hook +func (e EnvVar) Hooks() ([]Hook, error) { + return nil, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/filter.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/filter.go new file mode 100644 index 00000000..9de1c3fb --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/filter.go @@ -0,0 +1,62 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + +// Filter defines an interface for filtering discovered entities +type Filter interface { + DeviceIsSelected(device Device) bool +} + +// filtered represents a filtered discoverer +type filtered struct { + Discover + logger logger.Interface + filter Filter +} + +// newFilteredDiscoverer creates a discoverer that applies the specified filter to the returned entities of the discoverer +func newFilteredDiscoverer(logger logger.Interface, applyTo Discover, filter Filter) Discover { + return filtered{ + Discover: applyTo, + logger: logger, + filter: filter, + } +} + +// Devices returns a filtered list of devices based on the specified filter. +func (d filtered) Devices() ([]Device, error) { + devices, err := d.Discover.Devices() + if err != nil { + return nil, err + } + + if d.filter == nil { + return devices, nil + } + + var selected []Device + for _, device := range devices { + if d.filter.DeviceIsSelected(device) { + selected = append(selected, device) + } + d.logger.Debugf("skipping device %v", device) + } + + return selected, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/first-valid.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/first-valid.go new file mode 100644 index 00000000..81c93d3e --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/first-valid.go @@ -0,0 +1,85 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import "errors" + +type firstOf []Discover + +// FirstValid returns a discoverer that returns the first non-error result from a list of discoverers. +func FirstValid(discoverers ...Discover) Discover { + var f firstOf + for _, d := range discoverers { + if d == nil { + continue + } + f = append(f, d) + } + return f +} + +func (f firstOf) Devices() ([]Device, error) { + var errs error + for _, d := range f { + devices, err := d.Devices() + if err != nil { + errs = errors.Join(errs, err) + continue + } + return devices, nil + } + return nil, errs +} + +func (f firstOf) EnvVars() ([]EnvVar, error) { + var errs error + for _, d := range f { + envs, err := d.EnvVars() + if err != nil { + errs = errors.Join(errs, err) + continue + } + return envs, nil + } + return nil, errs +} + +func (f firstOf) Hooks() ([]Hook, error) { + var errs error + for _, d := range f { + hooks, err := d.Hooks() + if err != nil { + errs = errors.Join(errs, err) + continue + } + return hooks, nil + } + return nil, errs +} + +func (f firstOf) Mounts() ([]Mount, error) { + var errs error + for _, d := range f { + mounts, err := d.Mounts() + if err != nil { + errs = errors.Join(errs, err) + continue + } + return mounts, nil + } + return nil, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/gdrcopy.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/gdrcopy.go new file mode 100644 index 00000000..e6dcaec2 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/gdrcopy.go @@ -0,0 +1,27 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + +func NewGDRCopyDiscoverer(logger logger.Interface, devRoot string) (Discover, error) { + return NewCharDeviceDiscoverer( + logger, + devRoot, + []string{"/dev/gdrdrv"}, + ), nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/gds.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/gds.go new file mode 100644 index 00000000..cf762cd8 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/gds.go @@ -0,0 +1,80 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import ( + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" +) + +type gdsDeviceDiscoverer struct { + None + logger logger.Interface + devices Discover + mounts Discover +} + +// NewGDSDiscoverer creates a discoverer for GPUDirect Storage devices and mounts. +func NewGDSDiscoverer(logger logger.Interface, driverRoot string, devRoot string) (Discover, error) { + devices := NewCharDeviceDiscoverer( + logger, + devRoot, + []string{"/dev/nvidia-fs*"}, + ) + + udev := NewMounts( + logger, + lookup.NewDirectoryLocator(lookup.WithLogger(logger), lookup.WithRoot(driverRoot)), + driverRoot, + []string{"/run/udev"}, + ) + + cufile := NewMounts( + logger, + lookup.NewFileLocator( + lookup.WithLogger(logger), + lookup.WithRoot(driverRoot), + ), + driverRoot, + []string{"/etc/cufile.json"}, + ) + + d := gdsDeviceDiscoverer{ + logger: logger, + devices: devices, + mounts: Merge(udev, cufile), + } + + return &d, nil +} + +// Devices discovers the nvidia-fs device nodes for use with GPUDirect Storage +func (d *gdsDeviceDiscoverer) Devices() ([]Device, error) { + return d.devices.Devices() +} + +// Mounts discovers the required mounts for GPUDirect Storage. +// If no devices are discovered the discovered mounts are empty +func (d *gdsDeviceDiscoverer) Mounts() ([]Mount, error) { + devices, err := d.Devices() + if err != nil || len(devices) == 0 { + d.logger.Debugf("No nvidia-fs devices detected; skipping detection of mounts") + return nil, nil + } + + return d.mounts.Mounts() +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/graphics.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/graphics.go new file mode 100644 index 00000000..74f759ff --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/graphics.go @@ -0,0 +1,434 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/config/image" + "github.com/NVIDIA/nvidia-container-toolkit/internal/info/drm" + "github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root" +) + +// NewDRMNodesDiscoverer returns a discoverer for the DRM device nodes associated with the specified visible devices. +// +// TODO: The logic for creating DRM devices should be consolidated between this +// and the logic for generating CDI specs for a single device. This is only used +// when applying OCI spec modifications to an incoming spec in "legacy" mode. +func NewDRMNodesDiscoverer(logger logger.Interface, devices image.VisibleDevices, devRoot string, hookCreator HookCreator) (Discover, error) { + drmDeviceNodes, err := newDRMDeviceDiscoverer(logger, devices, devRoot) + if err != nil { + return nil, fmt.Errorf("failed to create DRM device discoverer: %v", err) + } + + drmByPathSymlinks := newCreateDRMByPathSymlinks(logger, drmDeviceNodes, devRoot, hookCreator) + + discover := Merge(drmDeviceNodes, drmByPathSymlinks) + return discover, nil +} + +// NewGraphicsMountsDiscoverer creates a discoverer for the mounts required by graphics tools such as vulkan. +func NewGraphicsMountsDiscoverer(logger logger.Interface, driver *root.Driver, hookCreator HookCreator) (Discover, error) { + libraries, err := newGraphicsLibrariesDiscoverer(logger, driver, hookCreator) + if err != nil { + return nil, fmt.Errorf("failed to construct discoverer for graphics libraries: %w", err) + } + + configs := NewMounts( + logger, + driver.Configs(), + driver.Root, + []string{ + "glvnd/egl_vendor.d/10_nvidia.json", + "egl/egl_external_platform.d/15_nvidia_gbm.json", + "egl/egl_external_platform.d/10_nvidia_wayland.json", + "nvidia/nvoptix.bin", + "X11/xorg.conf.d/10-nvidia.conf", + "X11/xorg.conf.d/nvidia-drm-outputclass.conf", + }, + ) + + discover := Merge( + libraries, + configs, + newVulkanConfigsDiscover(logger, driver), + ) + + return discover, nil +} + +// newVulkanConfigsDiscover creates a discoverer for vulkan ICD files. +// For these files we search the standard driver config paths as well as the +// driver root itself. This allows us to support GKE installations where the +// vulkan ICD files are at {{ .driverRoot }}/vulkan instead of in /etc/vulkan. +func newVulkanConfigsDiscover(logger logger.Interface, driver *root.Driver) Discover { + locator := lookup.First(driver.Configs(), driver.Files()) + + required := []string{ + "vulkan/icd.d/nvidia_icd.json", + "vulkan/icd.d/nvidia_layers.json", + "vulkan/implicit_layer.d/nvidia_layers.json", + } + // For some RPM-based driver packages, the vulkan ICD files are installed to + // /usr/share/vulkan/icd.d/nvidia_icd.%{_target_cpu}.json + // We also include this in the list of candidates for the ICD file. + switch runtime.GOARCH { + case "amd64": + required = append(required, "vulkan/icd.d/nvidia_icd.x86_64.json") + case "arm64": + required = append(required, "vulkan/icd.d/nvidia_icd.aarch64.json") + } + return &mountsToContainerPath{ + logger: logger, + locator: locator, + required: required, + containerRoot: "/etc", + } +} + +type graphicsDriverLibraries struct { + Discover + logger logger.Interface + hookCreator HookCreator +} + +var _ Discover = (*graphicsDriverLibraries)(nil) + +func newGraphicsLibrariesDiscoverer(logger logger.Interface, driver *root.Driver, hookCreator HookCreator) (Discover, error) { + cudaVersionPattern, err := driver.Version() + if err != nil { + return nil, fmt.Errorf("failed to get driver version: %w", err) + } + cudaLibRoot, err := driver.GetLibcudaParentDir() + if err != nil { + return nil, fmt.Errorf("failed to get libcuda.so parent directory: %w", err) + } + + libraries := NewMounts( + logger, + driver.Libraries(), + driver.Root, + []string{ + // The libnvidia-egl-gbm and libnvidia-egl-wayland libraries do not + // have the RM version. Use the *.* pattern to match X.Y.Z versions. + "libnvidia-egl-gbm.so.*.*", + "libnvidia-egl-wayland.so.*.*", + // We include the following libraries to have them available for + // symlink creation below: + // If CDI injection is used, these should already be detected as: + // * libnvidia-allocator.so.RM_VERSION + // * libnvidia-vulkan-producer.so.RM_VERSION + // but need to be handled for the legacy case too. + "libnvidia-allocator.so." + cudaVersionPattern, + "libnvidia-vulkan-producer.so." + cudaVersionPattern, + }, + ) + + xorgLibraries := NewMounts( + logger, + lookup.NewFileLocator( + lookup.WithLogger(logger), + lookup.WithRoot(driver.Root), + lookup.WithSearchPaths(buildXOrgSearchPaths(cudaLibRoot)...), + lookup.WithCount(1), + ), + driver.Root, + []string{ + "nvidia_drv.so", + "libglxserver_nvidia.so." + cudaVersionPattern, + }, + ) + + return &graphicsDriverLibraries{ + Discover: Merge(libraries, xorgLibraries), + logger: logger, + hookCreator: hookCreator, + }, nil +} + +// Mounts discovers the required libraries and filters out libnvidia-allocator.so. +// The library libnvidia-allocator.so is already handled by either the *.RM_VERSION +// injection or by libnvidia-container. We therefore filter it out here as a +// workaround for the case where libnvidia-container will re-mount this in the +// container, which causes issues with shared mount propagation. +func (d graphicsDriverLibraries) Mounts() ([]Mount, error) { + mounts, err := d.Discover.Mounts() + if err != nil { + return nil, fmt.Errorf("failed to get library mounts: %v", err) + } + + var filtered []Mount + for _, mount := range mounts { + if d.isDriverLibrary(filepath.Base(mount.Path), "libnvidia-allocator.so") { + continue + } + filtered = append(filtered, mount) + } + return filtered, nil +} + +// Create necessary library symlinks for graphics drivers +func (d graphicsDriverLibraries) Hooks() ([]Hook, error) { + mounts, err := d.Discover.Mounts() + if err != nil { + return nil, fmt.Errorf("failed to get library mounts: %v", err) + } + + var links []string + for _, mount := range mounts { + dir, filename := filepath.Split(mount.Path) + switch { + case d.isDriverLibrary(filename, "libnvidia-allocator.so"): + // gbm/nvidia-drm_gbm.so is a symlink to ../libnvidia-allocator.so.1 which + // in turn symlinks to libnvidia-allocator.so.RM_VERSION. + // The libnvidia-allocator.so.1 -> libnvidia-allocator.so.RM_VERSION symlink + // is created when ldconfig is run against the container and there + // is no explicit need to create it. + // create gbm/nvidia-drm_gbm.so -> ../libnvidia-allocate.so.1 symlink + linkPath := filepath.Join(dir, "gbm", "nvidia-drm_gbm.so") + links = append(links, fmt.Sprintf("%s::%s", "../libnvidia-allocator.so.1", linkPath)) + case d.isDriverLibrary(filename, "libnvidia-vulkan-producer.so"): + // libnvidia-vulkan-producer.so is a drirect symlink to libnvidia-vulkan-producer.so.RM_VERSION + // create libnvidia-vulkan-producer.so -> libnvidia-vulkan-producer.so.RM_VERSION symlink + linkPath := filepath.Join(dir, "libnvidia-vulkan-producer.so") + links = append(links, fmt.Sprintf("%s::%s", filename, linkPath)) + case d.isDriverLibrary(filename, "libglxserver_nvidia.so"): + // libglxserver_nvidia.so is a directl symlink to libglxserver_nvidia.so.RM_VERSION + // create libglxserver_nvidia.so -> libglxserver_nvidia.so.RM_VERSION symlink + linkPath := filepath.Join(dir, "libglxserver_nvidia.so") + links = append(links, fmt.Sprintf("%s::%s", filename, linkPath)) + } + } + if len(links) == 0 { + return nil, nil + } + + hook := d.hookCreator.Create("create-symlinks", links...) + + return hook.Hooks() +} + +// isDriverLibrary checks whether the specified filename is a specific driver library. +func (d graphicsDriverLibraries) isDriverLibrary(filename string, libraryName string) bool { + // TODO: Instead of `.*.*` we could use the driver version. + pattern := strings.TrimSuffix(libraryName, ".") + ".*.*" + match, _ := filepath.Match(pattern, filename) + return match +} + +// buildXOrgSearchPaths returns the ordered list of search paths for XOrg files. +func buildXOrgSearchPaths(libRoot string) []string { + var paths []string + if libRoot != "" { + paths = append(paths, + filepath.Join(libRoot, "nvidia/xorg"), + filepath.Join(libRoot, "xorg", "modules", "drivers"), + filepath.Join(libRoot, "xorg", "modules", "extensions"), + filepath.Join(libRoot, "xorg", "modules/updates", "drivers"), + filepath.Join(libRoot, "xorg", "modules/updates", "extensions"), + ) + } + + return append(paths, + filepath.Join("/usr/lib/xorg", "modules", "drivers"), + filepath.Join("/usr/lib/xorg", "modules", "extensions"), + filepath.Join("/usr/lib/xorg", "modules/updates", "drivers"), + filepath.Join("/usr/lib/xorg", "modules/updates", "extensions"), + filepath.Join("/usr/lib64/xorg", "modules", "drivers"), + filepath.Join("/usr/lib64/xorg", "modules", "extensions"), + filepath.Join("/usr/lib64/xorg", "modules/updates", "drivers"), + filepath.Join("/usr/lib64/xorg", "modules/updates", "extensions"), + filepath.Join("/usr/X11R6/lib", "modules", "drivers"), + filepath.Join("/usr/X11R6/lib", "modules", "extensions"), + filepath.Join("/usr/X11R6/lib", "modules/updates", "drivers"), + filepath.Join("/usr/X11R6/lib", "modules/updates", "extensions"), + filepath.Join("/usr/X11R6/lib64", "modules", "drivers"), + filepath.Join("/usr/X11R6/lib64", "modules", "extensions"), + filepath.Join("/usr/X11R6/lib64", "modules/updates", "drivers"), + filepath.Join("/usr/X11R6/lib64", "modules/updates", "extensions"), + ) +} + +type drmDevicesByPath struct { + None + logger logger.Interface + hookCreator HookCreator + devRoot string + devicesFrom Discover +} + +// newCreateDRMByPathSymlinks creates a discoverer for a hook to create the by-path symlinks for DRM devices discovered by the specified devices discoverer +func newCreateDRMByPathSymlinks(logger logger.Interface, devices Discover, devRoot string, hookCreator HookCreator) Discover { + d := drmDevicesByPath{ + logger: logger, + hookCreator: hookCreator, + devRoot: devRoot, + devicesFrom: devices, + } + + return &d +} + +// Hooks returns a hook to create the symlinks from the required CSV files +func (d drmDevicesByPath) Hooks() ([]Hook, error) { + devices, err := d.devicesFrom.Devices() + if err != nil { + return nil, fmt.Errorf("failed to discover devices for by-path symlinks: %v", err) + } + if len(devices) == 0 { + return nil, nil + } + links, err := d.getSpecificLinkArgs(devices) + if err != nil { + return nil, fmt.Errorf("failed to determine specific links: %v", err) + } + if len(links) == 0 { + return nil, nil + } + + var args []string + for _, l := range links { + args = append(args, "--link", l) + } + + hook := d.hookCreator.Create("create-symlinks", args...) + + return hook.Hooks() +} + +// getSpecificLinkArgs returns the required specific links that need to be created +func (d drmDevicesByPath) getSpecificLinkArgs(devices []Device) ([]string, error) { + selectedDevices := make(map[string]bool) + for _, d := range devices { + selectedDevices[filepath.Base(d.HostPath)] = true + } + + linkLocator := lookup.NewFileLocator( + lookup.WithLogger(d.logger), + lookup.WithRoot(d.devRoot), + ) + candidates, err := linkLocator.Locate("/dev/dri/by-path/pci-*-*") + if err != nil { + d.logger.Warningf("Failed to locate by-path links: %v; ignoring", err) + return nil, nil + } + + var links []string + for _, c := range candidates { + device, err := os.Readlink(c) + if err != nil { + d.logger.Warningf("Failed to evaluate symlink %v; ignoring", c) + continue + } + + if selectedDevices[filepath.Base(device)] { + d.logger.Debugf("adding device symlink %v -> %v", c, device) + links = append(links, fmt.Sprintf("%v::%v", device, c)) + } + } + + return links, nil +} + +// newDRMDeviceDiscoverer creates a discoverer for the DRM devices associated with the requested devices. +func newDRMDeviceDiscoverer(logger logger.Interface, devices image.VisibleDevices, devRoot string) (Discover, error) { + allDevices := NewCharDeviceDiscoverer( + logger, + devRoot, + []string{ + "/dev/dri/card*", + "/dev/dri/renderD*", + }, + ) + + filter, err := newDRMDeviceFilter(devices, devRoot) + if err != nil { + return nil, fmt.Errorf("failed to construct DRM device filter: %v", err) + } + + // We return a discoverer that applies the DRM device filter created above to all discovered DRM device nodes. + d := newFilteredDiscoverer( + logger, + allDevices, + filter, + ) + + return d, err +} + +// newDRMDeviceFilter creates a filter that matches DRM devices nodes for the visible devices. +func newDRMDeviceFilter(devices image.VisibleDevices, devRoot string) (Filter, error) { + gpuInformationPaths, err := proc.GetInformationFilePaths(devRoot) + if err != nil { + return nil, fmt.Errorf("failed to read GPU information: %v", err) + } + + var selectedBusIds []string + for _, f := range gpuInformationPaths { + info, err := proc.ParseGPUInformationFile(f) + if err != nil { + return nil, fmt.Errorf("failed to parse %v: %v", f, err) + } + uuid := info[proc.GPUInfoGPUUUID] + busID := info[proc.GPUInfoBusLocation] + minor := info[proc.GPUInfoDeviceMinor] + + if devices.Has(minor) || devices.Has(uuid) || devices.Has(busID) { + selectedBusIds = append(selectedBusIds, busID) + } + } + + filter := make(selectDeviceByPath) + for _, busID := range selectedBusIds { + drmDeviceNodes, err := drm.GetDeviceNodesByBusID(busID) + if err != nil { + return nil, fmt.Errorf("failed to determine DRM devices for %v: %v", busID, err) + } + for _, drmDeviceNode := range drmDeviceNodes { + filter[drmDeviceNode] = true + } + } + + return filter, nil +} + +// selectDeviceByPath is a filter that allows devices to be selected by the path +type selectDeviceByPath map[string]bool + +var _ Filter = (*selectDeviceByPath)(nil) + +// DeviceIsSelected determines whether the device's path has been selected +func (s selectDeviceByPath) DeviceIsSelected(device Device) bool { + return s[device.Path] +} + +// MountIsSelected is always true +func (s selectDeviceByPath) MountIsSelected(Mount) bool { + return true +} + +// HookIsSelected is always true +func (s selectDeviceByPath) HookIsSelected(Hook) bool { + return true +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/hooks.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/hooks.go new file mode 100644 index 00000000..b61c41d5 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/hooks.go @@ -0,0 +1,246 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import ( + "fmt" + "path/filepath" + + "tags.cncf.io/container-device-interface/pkg/cdi" +) + +// A HookName represents a supported CDI hooks. +type HookName string + +const ( + // AllHooks is a special hook name that allows all hooks to be matched. + AllHooks = HookName("all") + + // A ChmodHook is used to set the file mode of the specified paths. + // Deprecated: The chmod hook is deprecated and will be removed in a future release. + ChmodHook = HookName("chmod") + // A CreateSymlinksHook is used to create symlinks in the container. + CreateSymlinksHook = HookName("create-symlinks") + // DisableDeviceNodeModificationHook refers to the hook used to ensure that + // device nodes are not created by libnvidia-ml.so or nvidia-smi in a + // container. + // Added in v1.17.8 + DisableDeviceNodeModificationHook = HookName("disable-device-node-modification") + // An EnableCudaCompatHook is used to enabled CUDA Forward Compatibility. + // Added in v1.17.5 + EnableCudaCompatHook = HookName("enable-cuda-compat") + // An UpdateLDCacheHook is the hook used to update the ldcache in the + // container. This allows injected libraries to be discoverable. + UpdateLDCacheHook = HookName("update-ldcache") + + defaultNvidiaCDIHookPath = "/usr/bin/nvidia-cdi-hook" +) + +// defaultDisabledHooks defines hooks that are disabled by default. +// These hooks can be explicitly enabled using the WithEnabledHooks option. +var defaultDisabledHooks = []HookName{ + // ChmodHook is disabled by default as it was a workaround for older + // versions of crun that has since been fixed. + ChmodHook, +} + +var _ Discover = (*Hook)(nil) + +// Devices returns an empty list of devices for a Hook discoverer. +func (h *Hook) Devices() ([]Device, error) { + return nil, nil +} + +// EnvVars returns an empty list of envs for a Hook discoverer. +func (h *Hook) EnvVars() ([]EnvVar, error) { + return nil, nil +} + +// Mounts returns an empty list of mounts for a Hook discoverer. +func (h *Hook) Mounts() ([]Mount, error) { + return nil, nil +} + +// Hooks allows the Hook type to also implement the Discoverer interface. +// It returns a single hook +func (h *Hook) Hooks() ([]Hook, error) { + if h == nil { + return nil, nil + } + + return []Hook{*h}, nil +} + +type hookCreatorOptions struct { + nvidiaCDIHookPath string + disabledHooks []HookName + enabledHooks []HookName + debugLogging bool +} + +type Option func(*hookCreatorOptions) + +type cdiHookCreator struct { + nvidiaCDIHookPath string + disabledHooks map[HookName]bool + + fixedArgs []string + debugLogging bool +} + +// An allDisabledHookCreator is a HookCreator that does not create any hooks. +type allDisabledHookCreator struct{} + +// Create returns nil for all hooks for an allDisabledHookCreator. +func (a *allDisabledHookCreator) Create(name HookName, args ...string) *Hook { + return nil +} + +// A HookCreator defines an interface for creating discover hooks. +type HookCreator interface { + Create(HookName, ...string) *Hook +} + +func WithDebugLogging(debugLogging bool) Option { + return func(hco *hookCreatorOptions) { + hco.debugLogging = debugLogging + } +} + +// WithDisabledHooks explicitly disables the specified hooks. +// This can be specified multiple times. +func WithDisabledHooks(hooks ...HookName) Option { + return func(c *hookCreatorOptions) { + c.disabledHooks = append(c.disabledHooks, hooks...) + } +} + +// WithEnabledHooks explicitly enables the specified hooks. +// This is useful for enabling hooks that are disabled by default. +func WithEnabledHooks(hooks ...HookName) Option { + return func(c *hookCreatorOptions) { + c.enabledHooks = append(c.enabledHooks, hooks...) + } +} + +// WithNVIDIACDIHookPath sets the path to the nvidia-cdi-hook binary. +func WithNVIDIACDIHookPath(nvidiaCDIHookPath string) Option { + return func(c *hookCreatorOptions) { + c.nvidiaCDIHookPath = nvidiaCDIHookPath + } +} + +func NewHookCreator(opts ...Option) HookCreator { + o := &hookCreatorOptions{ + nvidiaCDIHookPath: defaultNvidiaCDIHookPath, + } + for _, opt := range opts { + opt(o) + } + + o.disabledHooks = append(o.disabledHooks, defaultDisabledHooks...) + + disabledHooks := make(map[HookName]bool) + for _, h := range o.disabledHooks { + disabledHooks[h] = true + } + + if disabledHooks[AllHooks] && len(o.enabledHooks) == 0 { + return &allDisabledHookCreator{} + } + + for _, h := range o.enabledHooks { + disabledHooks[h] = false + } + + c := &cdiHookCreator{ + nvidiaCDIHookPath: o.nvidiaCDIHookPath, + disabledHooks: disabledHooks, + fixedArgs: getFixedArgsForCDIHookCLI(o.nvidiaCDIHookPath), + debugLogging: o.debugLogging, + } + + return c +} + +// Create creates a new hook with the given name and arguments. +// If a hook is disabled, a nil hook is returned. +func (c cdiHookCreator) Create(name HookName, args ...string) *Hook { + if c.isDisabled(name, args...) { + return nil + } + + return &Hook{ + Lifecycle: cdi.CreateContainerHook, + Path: c.nvidiaCDIHookPath, + Args: append(c.requiredArgs(name), c.transformArgs(name, args...)...), + Env: []string{fmt.Sprintf("NVIDIA_CTK_DEBUG=%v", c.debugLogging)}, + } +} + +func (c cdiHookCreator) isDisabled(name HookName, args ...string) bool { + disabled, ok := c.disabledHooks[name] + if ok { + return disabled + } + if c.disabledHooks[AllHooks] { + return true + } + + // still reject hooks that require args if none were provided + switch name { + case CreateSymlinksHook, ChmodHook: + return len(args) == 0 + } + return false +} + +func (c cdiHookCreator) requiredArgs(name HookName) []string { + return append(c.fixedArgs, string(name)) +} + +func (c cdiHookCreator) transformArgs(name HookName, args ...string) []string { + switch name { + case CreateSymlinksHook: + var transformedArgs []string + for _, arg := range args { + transformedArgs = append(transformedArgs, "--link", arg) + } + return transformedArgs + case ChmodHook: + var transformedArgs = []string{"--mode", "755"} + for _, arg := range args { + transformedArgs = append(transformedArgs, "--path", arg) + } + return transformedArgs + default: + return args + } +} + +// getFixedArgsForCDIHookCLI returns the fixed arguments for the hook CLI. +// If the nvidia-ctk binary is used, hooks are implemented under the hook +// subcommand. +// For the nvidia-cdi-hook binary, the hooks are implemented as subcommands of +// the top-level CLI. +func getFixedArgsForCDIHookCLI(nvidiaCDIHookPath string) []string { + base := filepath.Base(nvidiaCDIHookPath) + if base == "nvidia-ctk" { + return []string{base, "hook"} + } + return []string{base} +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/ipc.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/ipc.go new file mode 100644 index 00000000..f636290f --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/ipc.go @@ -0,0 +1,78 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import ( + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" +) + +type ipcMounts mounts + +// NewIPCDiscoverer creats a discoverer for NVIDIA IPC sockets. +func NewIPCDiscoverer(logger logger.Interface, driverRoot string) (Discover, error) { + sockets := newMounts( + logger, + lookup.NewFileLocator( + lookup.WithLogger(logger), + lookup.WithRoot(driverRoot), + lookup.WithSearchPaths("/run", "/var/run"), + lookup.WithCount(1), + ), + driverRoot, + []string{ + "/nvidia-persistenced/socket", + "/nvidia-fabricmanager/socket", + }, + ) + + mps := newMounts( + logger, + lookup.NewFileLocator( + lookup.WithLogger(logger), + lookup.WithRoot(driverRoot), + lookup.WithCount(1), + ), + driverRoot, + []string{ + "/tmp/nvidia-mps", + }, + ) + + d := Merge( + (*ipcMounts)(sockets), + (*ipcMounts)(mps), + ) + return d, nil +} + +// Mounts returns the discovered mounts with "noexec" added to the mount options. +func (d *ipcMounts) Mounts() ([]Mount, error) { + mounts, err := (*mounts)(d).Mounts() + if err != nil { + return nil, err + } + + var modifiedMounts []Mount + for _, m := range mounts { + mount := m + mount.Options = append(mount.Options, "noexec") + modifiedMounts = append(modifiedMounts, mount) + } + + return modifiedMounts, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/ldconfig.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/ldconfig.go new file mode 100644 index 00000000..54ac608e --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/ldconfig.go @@ -0,0 +1,113 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +// NewLDCacheUpdateHook creates a discoverer that updates the ldcache for the specified mounts. A logger can also be specified +func NewLDCacheUpdateHook(logger logger.Interface, mounts Discover, hookCreator HookCreator, ldconfigPath string) (Discover, error) { + d := ldconfig{ + logger: logger, + hookCreator: hookCreator, + ldconfigPath: ldconfigPath, + mountsFrom: mounts, + } + + return &d, nil +} + +type ldconfig struct { + None + logger logger.Interface + hookCreator HookCreator + ldconfigPath string + mountsFrom Discover +} + +// Hooks checks the required mounts for libraries and returns a hook to update the LDcache for the discovered paths. +func (d ldconfig) Hooks() ([]Hook, error) { + mounts, err := d.mountsFrom.Mounts() + if err != nil { + return nil, fmt.Errorf("failed to discover mounts for ldcache update: %v", err) + } + + var args []string + + if d.ldconfigPath != "" { + args = append(args, "--ldconfig-path", d.ldconfigPath) + } + + for _, f := range uniqueFolders(getLibraryPaths(mounts)) { + args = append(args, "--folder", f) + } + + return d.hookCreator.Create(UpdateLDCacheHook, args...).Hooks() +} + +// getLibraryPaths extracts the library dirs from the specified mounts +func getLibraryPaths(mounts []Mount) []string { + var paths []string + for _, m := range mounts { + if !isLibName(m.Path) { + continue + } + paths = append(paths, m.Path) + } + return paths +} + +// isLibName checks if the specified filename is a library (i.e. ends in `.so*`) +func isLibName(filename string) bool { + base := filepath.Base(filename) + + isLib, err := filepath.Match("lib?*.so*", base) + if !isLib || err != nil { + return false + } + + parts := strings.Split(base, ".so") + if len(parts) == 1 { + return true + } + + return parts[len(parts)-1] == "" || strings.HasPrefix(parts[len(parts)-1], ".") +} + +// uniqueFolders returns the unique set of folders for the specified files +func uniqueFolders(libraries []string) []string { + var paths []string + checked := make(map[string]bool) + + for _, l := range libraries { + dir := filepath.Dir(l) + if dir == "" { + continue + } + if checked[dir] { + continue + } + checked[dir] = true + paths = append(paths, dir) + } + return paths +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/list.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/list.go new file mode 100644 index 00000000..83d37b79 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/list.go @@ -0,0 +1,99 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package discover + +import "fmt" + +// list is a discoverer that contains a list of Discoverers. The output of the +// Mounts functions is the concatenation of the output for each of the +// elements in the list. +type list []Discover + +var _ Discover = (*list)(nil) + +// Merge creates a discoverer that is the composite of a list of discoverers. +func Merge(discoverers ...Discover) Discover { + var l list + for _, d := range discoverers { + if d == nil { + continue + } + l = append(l, d) + } + + return l +} + +// Devices returns all devices from the included discoverers +func (d list) Devices() ([]Device, error) { + var allDevices []Device + + for i, di := range d { + devices, err := di.Devices() + if err != nil { + return nil, fmt.Errorf("error discovering devices for discoverer %v: %v", i, err) + } + allDevices = append(allDevices, devices...) + } + + return allDevices, nil +} + +// EnvVars returns all environment variables from the included discoverers. +func (d list) EnvVars() ([]EnvVar, error) { + var allEnvs []EnvVar + + for i, di := range d { + envs, err := di.EnvVars() + if err != nil { + return nil, fmt.Errorf("error discovering envs for discoverer %v: %w", i, err) + } + allEnvs = append(allEnvs, envs...) + } + + return allEnvs, nil +} + +// Mounts returns all mounts from the included discoverers +func (d list) Mounts() ([]Mount, error) { + var allMounts []Mount + + for i, di := range d { + mounts, err := di.Mounts() + if err != nil { + return nil, fmt.Errorf("error discovering mounts for discoverer %v: %v", i, err) + } + allMounts = append(allMounts, mounts...) + } + + return allMounts, nil +} + +// Hooks returns all Hooks from the included discoverers +func (d list) Hooks() ([]Hook, error) { + var allHooks []Hook + + for i, di := range d { + hooks, err := di.Hooks() + if err != nil { + return nil, fmt.Errorf("error discovering hooks for discoverer %v: %v", i, err) + } + allHooks = append(allHooks, hooks...) + } + + return allHooks, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/mofed.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/mofed.go new file mode 100644 index 00000000..b9ff4153 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/mofed.go @@ -0,0 +1,33 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + +// NewMOFEDDiscoverer creates a discoverer for MOFED devices. +func NewMOFEDDiscoverer(logger logger.Interface, devRoot string) (Discover, error) { + devices := NewCharDeviceDiscoverer( + logger, + devRoot, + []string{ + "/dev/infiniband/uverbs*", + "/dev/infiniband/rdma_cm", + }, + ) + + return devices, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/mounts-to-container-path.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/mounts-to-container-path.go new file mode 100644 index 00000000..d92bc91c --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/mounts-to-container-path.go @@ -0,0 +1,82 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" +) + +// mountsToContainerPath defines a Discoverer for a required set of mounts. +// When these are discovered by a locator the specified container root is used +// to construct the container path for the mount returned. +type mountsToContainerPath struct { + None + logger logger.Interface + locator lookup.Locator + required []string + containerRoot string +} + +func (d *mountsToContainerPath) Mounts() ([]Mount, error) { + seen := make(map[string]bool) + var mounts []Mount + for _, target := range d.required { + if strings.Contains(target, "*") { + // TODO: We could relax this condition. + return nil, fmt.Errorf("wildcard patterns are not supported: %s", target) + } + candidates, err := d.locator.Locate(target) + if err != nil { + d.logger.Warningf("Could not locate %v: %v", target, err) + continue + } + if len(candidates) == 0 { + d.logger.Warningf("Missing %v", target) + continue + } + hostPath := candidates[0] + if seen[hostPath] { + d.logger.Debugf("Skipping duplicate mount %v", hostPath) + continue + } + seen[hostPath] = true + d.logger.Debugf("Located %v as %v", target, hostPath) + + containerPath := filepath.Join(d.containerRoot, target) + d.logger.Infof("Selecting %v as %v", hostPath, containerPath) + + mount := Mount{ + HostPath: hostPath, + Path: containerPath, + Options: []string{ + "ro", + "nosuid", + "nodev", + "rbind", + "rprivate", + }, + } + mounts = append(mounts, mount) + } + + return mounts, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/mounts.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/mounts.go new file mode 100644 index 00000000..7eb41a38 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/mounts.go @@ -0,0 +1,113 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package discover + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" +) + +// mounts is a generic discoverer for Mounts. It is customized by specifying the +// required entities as a list and a Locator that is used to find the target mounts +// based on the entry in the list. +type mounts struct { + None + logger logger.Interface + lookup lookup.Locator + root string + required []string +} + +var _ Discover = (*mounts)(nil) + +// NewMounts creates a discoverer for the required mounts using the specified locator. +func NewMounts(logger logger.Interface, lookup lookup.Locator, root string, required []string) Discover { + return WithCache(newMounts(logger, lookup, root, required)) +} + +// newMounts creates a discoverer for the required mounts using the specified locator. +func newMounts(logger logger.Interface, lookup lookup.Locator, root string, required []string) *mounts { + return &mounts{ + logger: logger, + lookup: lookup, + root: filepath.Join("/", root), + required: required, + } +} + +func (d *mounts) Mounts() ([]Mount, error) { + if d.lookup == nil { + return nil, fmt.Errorf("no lookup defined") + } + + var mounts []Mount + seen := make(map[string]bool) + for _, candidate := range d.required { + d.logger.Debugf("Locating %v", candidate) + located, err := d.lookup.Locate(candidate) + if err != nil { + d.logger.Warningf("Could not locate %v: %v", candidate, err) + continue + } + if len(located) == 0 { + d.logger.Warningf("Missing %v", candidate) + continue + } + d.logger.Debugf("Located %v as %v", candidate, located) + for _, p := range located { + if seen[p] { + d.logger.Debugf("Skipping duplicate mount %v", p) + continue + } + + r := d.relativeTo(p) + if r == "" { + r = p + } + + d.logger.Infof("Selecting %v as %v", p, r) + mount := Mount{ + HostPath: p, + Path: r, + Options: []string{ + "ro", + "nosuid", + "nodev", + "rbind", + "rprivate", + }, + } + mounts = append(mounts, mount) + seen[p] = true + } + } + + return mounts, nil +} + +// relativeTo returns the path relative to the root for the file locator +func (d *mounts) relativeTo(path string) string { + if d.root == "/" { + return path + } + + return strings.TrimPrefix(path, d.root) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/none.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/none.go new file mode 100644 index 00000000..3ce62472 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/none.go @@ -0,0 +1,43 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package discover + +// None is a null discoverer that returns an empty list of devices and +// mounts. +type None struct{} + +var _ Discover = (*None)(nil) + +// Devices returns an empty list of devices +func (e None) Devices() ([]Device, error) { + return nil, nil +} + +// EnvVars returns an empty list of devices +func (e None) EnvVars() ([]EnvVar, error) { + return nil, nil +} + +// Mounts returns an empty list of mounts +func (e None) Mounts() ([]Mount, error) { + return nil, nil +} + +// Hooks returns an empty list of hooks +func (e None) Hooks() ([]Hook, error) { + return nil, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/nvswitch.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/nvswitch.go new file mode 100644 index 00000000..fb956d11 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/nvswitch.go @@ -0,0 +1,33 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + +// NewNvSwitchDiscoverer creates a discoverer for NVSWITCH devices. +func NewNvSwitchDiscoverer(logger logger.Interface, devRoot string) (Discover, error) { + devices := NewCharDeviceDiscoverer( + logger, + devRoot, + []string{ + "/dev/nvidia-nvswitchctl", + "/dev/nvidia-nvswitch*", + }, + ) + + return devices, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/symlinks.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/symlinks.go new file mode 100644 index 00000000..e4aa26e6 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/discover/symlinks.go @@ -0,0 +1,244 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package discover + +import ( + "debug/elf" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +type Symlink struct { + target string + link string +} + +func (s *Symlink) String() string { + return fmt.Sprintf("%s::%s", s.target, s.link) +} + +type additionalSymlinks struct { + logger logger.Interface + Discover + version string + hookCreator HookCreator +} + +// WithDriverDotSoSymlinks decorates the provided discoverer. +// A hook is added that checks for specific driver symlinks that need to be created. +func WithDriverDotSoSymlinks(logger logger.Interface, mounts Discover, version string, hookCreator HookCreator) Discover { + if version == "" { + version = "*.*" + } + return &additionalSymlinks{ + logger: logger, + Discover: mounts, + hookCreator: hookCreator, + version: version, + } +} + +// Hooks returns a hook to create the additional symlinks based on the mounts. +func (d *additionalSymlinks) Hooks() ([]Hook, error) { + mounts, err := d.Mounts() + if err != nil { + return nil, fmt.Errorf("failed to get library mounts: %v", err) + } + hooks, err := d.Discover.Hooks() + if err != nil { + return nil, fmt.Errorf("failed to get hooks: %v", err) + } + + var links []string + processedPaths := make(map[string]bool) + processedLinks := make(map[string]bool) + for _, mount := range mounts { + if processedPaths[mount.Path] { + continue + } + processedPaths[mount.Path] = true + + linksForMount := d.getLinksForMount(mount.Path) + soSymlinks, err := d.getDotSoSymlinks(mount.HostPath, mount.Path) + if err != nil { + d.logger.Warningf("Failed to get soname symlinks for %+v: %v", mount, err) + } + linksForMount = append(linksForMount, soSymlinks...) + + for _, link := range linksForMount { + if processedLinks[link] { + continue + } + processedLinks[link] = true + links = append(links, link) + } + } + + if len(links) == 0 { + return hooks, nil + } + + createSymlinkHooks, err := d.hookCreator.Create("create-symlinks", links...).Hooks() + if err != nil { + return nil, fmt.Errorf("failed to create symlink hook: %v", err) + } + + return append(hooks, createSymlinkHooks...), nil +} + +// getLinksForMount maps the path to created links if any. +func (d additionalSymlinks) getLinksForMount(path string) []string { + dir, filename := filepath.Split(path) + switch { + case d.isDriverLibrary("libcuda.so", filename): + // XXX Many applications wrongly assume that libcuda.so exists (e.g. with dlopen). + // create libcuda.so -> libcuda.so.1 symlink + link := fmt.Sprintf("%s::%s", "libcuda.so.1", filepath.Join(dir, "libcuda.so")) + return []string{link} + case d.isDriverLibrary("libGLX_nvidia.so", filename): + // XXX GLVND requires this symlink for indirect GLX support. + // create libGLX_indirect.so.0 -> libGLX_nvidia.so.VERSION symlink + link := fmt.Sprintf("%s::%s", filename, filepath.Join(dir, "libGLX_indirect.so.0")) + return []string{link} + case d.isDriverLibrary("libnvidia-opticalflow.so", filename): + // XXX Fix missing symlink for libnvidia-opticalflow.so. + // create libnvidia-opticalflow.so -> libnvidia-opticalflow.so.1 symlink + link := fmt.Sprintf("%s::%s", "libnvidia-opticalflow.so.1", filepath.Join(dir, "libnvidia-opticalflow.so")) + return []string{link} + } + return nil +} + +// isDriverLibrary checks whether the specified filename is a specific driver library. +func (d additionalSymlinks) isDriverLibrary(libraryName string, filename string) bool { + pattern := libraryName + "." + d.version + match, _ := filepath.Match(pattern, filename) + return match +} + +func (d *additionalSymlinks) getDotSoSymlinks(hostLibraryPath string, libraryContainerPath string) ([]string, error) { + hostLibraryDir := filepath.Dir(hostLibraryPath) + containerLibraryDir, libraryName := filepath.Split(libraryContainerPath) + if !d.isDriverLibrary("*", libraryName) { + return nil, nil + } + + soname, err := getSoname(hostLibraryPath) + if err != nil { + return nil, err + } + + var soSymlinks []string + // Create the SONAME -> libraryName symlink. + // If the soname matches the library path, or the expected SONAME link does + // not exist on the host, we do not create it in the container. + if soname != libraryName && d.linkExistsInDir(hostLibraryDir, soname) { + s := Symlink{ + target: libraryName, + link: filepath.Join(containerLibraryDir, soname), + } + soSymlinks = append(soSymlinks, s.String()) + } + + soTarget := soname + if soTarget == "" { + soTarget = libraryName + } + // Create the .so -> SONAME symlink. + // If the .so link name matches the SONAME link, or the expected .so link + // does not exist on the host, we do not create it in the container. + if soLink := getSoLink(soTarget); soLink != soTarget && d.linkExistsInDir(hostLibraryDir, soLink) { + s := Symlink{ + target: soTarget, + link: filepath.Join(containerLibraryDir, soLink), + } + soSymlinks = append(soSymlinks, s.String()) + } + return soSymlinks, nil +} + +func (d *additionalSymlinks) linkExistsInDir(dir string, link string) bool { + if link == "" { + return false + } + linkPath := filepath.Join(dir, link) + exists, err := linkExists(linkPath) + if err != nil { + d.logger.Warningf("Failed to check symlink %q: %v", linkPath, err) + return false + } + return exists +} + +// linkExists returns true if the specified symlink exists. +// We use a function variable here to allow this to be overridden for testing. +var linkExists = func(linkPath string) (bool, error) { + info, err := os.Lstat(linkPath) + if os.IsNotExist(err) { + return false, nil + } + if err != nil { + return false, err + } + // The linkPath is a symlink. + if info.Mode()&os.ModeSymlink != 0 { + return true, nil + } + + return false, nil +} + +// getSoname returns the soname for the specified library path. +// We use a function variable here to allow this to be overridden for testing. +var getSoname = func(libraryPath string) (string, error) { + lib, err := elf.Open(libraryPath) + if err != nil { + return "", err + } + defer lib.Close() + + sonames, err := lib.DynString(elf.DT_SONAME) + if err != nil { + return "", err + } + if len(sonames) > 1 { + return "", fmt.Errorf("multiple SONAMEs detected for %v: %v", libraryPath, sonames) + } + if len(sonames) == 0 { + return filepath.Base(libraryPath), nil + } + return sonames[0], nil +} + +// getSoLink returns the filename for the .so symlink that should point to the +// soname symlink for the specified library. +// If the soname / library name does not end in a `.so[.*]` then an empty string +// is returned. +func getSoLink(soname string) string { + ext := filepath.Ext(soname) + if ext == "" { + return "" + } + if ext == ".so" { + return soname + } + return getSoLink(strings.TrimSuffix(soname, ext)) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/api.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/api.go new file mode 100644 index 00000000..ed70bb4f --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/api.go @@ -0,0 +1,55 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package dxcore + +// dxcore stores a reference the dxcore dynamic library +var dxcore *context + +// Init initializes the dxcore dynamic library +func Init() error { + c, err := initContext() + if err != nil { + return err + } + dxcore = c + return nil +} + +// Shutdown closes the dxcore dynamic library +func Shutdown() error { + if dxcore != nil && dxcore.initialized != 0 { + dxcore.deinitContext() + } + return nil +} + +// GetDriverStorePaths returns the list of driver store paths +func GetDriverStorePaths() []string { + var paths []string + selected := make(map[string]bool) + + for i := 0; i < dxcore.getAdapterCount(); i++ { + path := dxcore.getAdapter(i).getDriverStorePath() + if selected[path] { + continue + } + selected[path] = true + paths = append(paths, path) + } + + return paths +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/dxcore.c b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/dxcore.c new file mode 100644 index 00000000..a7c9a6b7 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/dxcore.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + */ + +#include +#include + +#include "dxcore.h" + +// We define log_write as an empty macro to allow dxcore to remain unchanged. +#define log_write(...) + +// We define the following macros to allow dxcore to remain largely unchanged. +#define log_info(msg) log_write('I', __FILE__, __LINE__, msg) +#define log_warn(msg) log_write('W', __FILE__, __LINE__, msg) +#define log_err(msg) log_write('E', __FILE__, __LINE__, msg) +#define log_infof(fmt, ...) log_write('I', __FILE__, __LINE__, fmt, __VA_ARGS__) +#define log_warnf(fmt, ...) log_write('W', __FILE__, __LINE__, fmt, __VA_ARGS__) +#define log_errf(fmt, ...) log_write('E', __FILE__, __LINE__, fmt, __VA_ARGS__) + + +#define DXCORE_MAX_PATH 260 + +/* + * List of components we expect to find in the driver store that we need to mount + */ +static const char * const dxcore_nvidia_driver_store_components[] = { + "libcuda.so.1.1", /* Core library for cuda support */ + "libcuda_loader.so", /* Core library for cuda support on WSL */ + "libnvidia-ptxjitcompiler.so.1", /* Core library for PTX Jit support */ + "libnvidia-ml.so.1", /* Core library for nvml */ + "libnvidia-ml_loader.so", /* Core library for nvml on WSL */ + "nvidia-smi", /* nvidia-smi binary*/ + "nvcubins.bin", /* Binary containing GPU code for cuda */ +}; + + +/* + * List of functions and structures we need to communicate with libdxcore. + * Documentation on these functions can be found on docs.microsoft.com in d3dkmthk. + */ + +struct dxcore_enumAdapters2; +struct dxcore_enumAdapters3; +struct dxcore_queryAdapterInfo; + +typedef int(*pfnDxcoreEnumAdapters2)(struct dxcore_enumAdapters2* pParams); +typedef int(*pfnDxcoreEnumAdapters3)(struct dxcore_enumAdapters3* pParams); +typedef int(*pfnDxcoreQueryAdapterInfo)(struct dxcore_queryAdapterInfo* pParams); + +struct dxcore_lib { + void* hDxcoreLib; + pfnDxcoreEnumAdapters2 pDxcoreEnumAdapters2; + pfnDxcoreEnumAdapters3 pDxcoreEnumAdapters3; + pfnDxcoreQueryAdapterInfo pDxcoreQueryAdapterInfo; +}; + +struct dxcore_adapterInfo +{ + unsigned int hAdapter; + struct dxcore_luid AdapterLuid; + unsigned int NumOfSources; + unsigned int bPresentMoveRegionsPreferred; +}; + +struct dxcore_enumAdapters2 +{ + unsigned int NumAdapters; + struct dxcore_adapterInfo *pAdapters; +}; + +#define ENUMADAPTER3_FILTER_COMPUTE_ONLY (0x0000000000000001) + +struct dxcore_enumAdapters3 +{ + unsigned long long Filter; + unsigned int NumAdapters; + struct dxcore_adapterInfo *pAdapters; +}; + +enum dxcore_kmtqueryAdapterInfoType +{ + DXCORE_QUERYDRIVERVERSION = 13, + DXCORE_QUERYREGISTRY = 48, +}; + +enum dxcore_queryregistry_type { + DXCORE_QUERYREGISTRY_DRIVERSTOREPATH = 2, + DXCORE_QUERYREGISTRY_DRIVERIMAGEPATH = 3, +}; + +enum dxcore_queryregistry_status { + DXCORE_QUERYREGISTRY_STATUS_SUCCESS = 0, + DXCORE_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW = 1, + DXCORE_QUERYREGISTRY_STATUS_FAIL = 2, +}; + +struct dxcore_queryregistry_info { + enum dxcore_queryregistry_type QueryType; + unsigned int QueryFlags; + wchar_t ValueName[DXCORE_MAX_PATH]; + unsigned int ValueType; + unsigned int PhysicalAdapterIndex; + unsigned int OutputValueSize; + enum dxcore_queryregistry_status Status; + union { + unsigned long long OutputQword; + wchar_t Output; + }; +}; + +struct dxcore_queryAdapterInfo +{ + unsigned int hAdapter; + enum dxcore_kmtqueryAdapterInfoType Type; + void *pPrivateDriverData; + unsigned int PrivateDriverDataSize; +}; + +static int dxcore_query_adapter_info_helper(struct dxcore_lib* pLib, + unsigned int hAdapter, + enum dxcore_kmtqueryAdapterInfoType type, + void* pPrivateDriverDate, + unsigned int privateDriverDataSize) +{ + struct dxcore_queryAdapterInfo queryAdapterInfo = { 0 }; + + queryAdapterInfo.hAdapter = hAdapter; + queryAdapterInfo.Type = type; + queryAdapterInfo.pPrivateDriverData = pPrivateDriverDate; + queryAdapterInfo.PrivateDriverDataSize = privateDriverDataSize; + + return pLib->pDxcoreQueryAdapterInfo(&queryAdapterInfo); +} + +static int dxcore_query_adapter_wddm_version(struct dxcore_lib* pLib, unsigned int hAdapter, unsigned int* version) +{ + return dxcore_query_adapter_info_helper(pLib, + hAdapter, + DXCORE_QUERYDRIVERVERSION, + (void*)version, + sizeof(*version)); +} + +static int dxcore_query_adapter_driverstore(struct dxcore_lib* pLib, unsigned int hAdapter, char** ppDriverStorePath) +{ + struct dxcore_queryregistry_info params = {0}; + struct dxcore_queryregistry_info* pValue = NULL; + wchar_t* pOutput; + size_t outputSizeInBytes; + size_t outputSize; + + params.QueryType = DXCORE_QUERYREGISTRY_DRIVERSTOREPATH; + + if (dxcore_query_adapter_info_helper(pLib, + hAdapter, + DXCORE_QUERYREGISTRY, + (void*)¶ms, + sizeof(params))) + { + log_err("Failed to query driver store path size for the WDDM Adapter"); + return (-1); + } + + if (params.OutputValueSize > DXCORE_MAX_PATH * sizeof(wchar_t)) { + log_err("The driver store path size returned by dxcore is not valid"); + return (-1); + } + + outputSizeInBytes = (size_t)params.OutputValueSize; + outputSize = outputSizeInBytes / sizeof(wchar_t); + + pValue = calloc(sizeof(struct dxcore_queryregistry_info) + outputSizeInBytes + sizeof(wchar_t), 1); + if (!pValue) { + log_err("Out of memory while allocating temp buffer to query adapter info"); + return (-1); + } + + pValue->QueryType = DXCORE_QUERYREGISTRY_DRIVERSTOREPATH; + pValue->OutputValueSize = (unsigned int)outputSizeInBytes; + + if (dxcore_query_adapter_info_helper(pLib, + hAdapter, + DXCORE_QUERYREGISTRY, + (void*)pValue, + (unsigned int)(sizeof(struct dxcore_queryregistry_info) + outputSizeInBytes))) + { + log_err("Failed to query driver store path data for the WDDM Adapter"); + free(pValue); + return (-1); + } + pOutput = (wchar_t*)(&pValue->Output); + + // Make sure no matter what happened the wchar_t string is null terminated + pOutput[outputSize] = L'\0'; + + // Convert the output into a regular c string + *ppDriverStorePath = (char*)calloc(outputSize + 1, sizeof(char)); + if (!*ppDriverStorePath) { + log_err("Out of memory while allocating the buffer for the driver store path"); + free(pValue); + return (-1); + } + wcstombs(*ppDriverStorePath, pOutput, outputSize); + + free(pValue); + + return 0; +} + +static void dxcore_add_adapter(struct dxcore_context* pCtx, struct dxcore_lib* pLib, struct dxcore_adapterInfo *pAdapterInfo) +{ + unsigned int wddmVersion = 0; + char* driverStorePath = NULL; + + log_infof("Creating a new WDDM Adapter for hAdapter:%x luid:%llx", pAdapterInfo->hAdapter, *((unsigned long long*)&pAdapterInfo->AdapterLuid)); + + if (dxcore_query_adapter_wddm_version(pLib, pAdapterInfo->hAdapter, &wddmVersion)) { + log_err("Failed to query the WDDM version for the specified adapter. Skipping it."); + return; + } + + if (wddmVersion < 2700) { + log_err("Found a WDDM adapter running a driver with pre-WDDM 2.7 . Skipping it."); + return; + } + + if (dxcore_query_adapter_driverstore(pLib, pAdapterInfo->hAdapter, &driverStorePath)) { + log_err("Failed to query driver store path for the WDDM Adapter . Skipping it."); + return; + } + + // We got all the info we needed. Adding it to the tracking structure. + { + struct dxcore_adapter* newList; + newList = realloc(pCtx->adapterList, sizeof(struct dxcore_adapter) * (pCtx->adapterCount + 1)); + if (!newList) { + log_err("Out of memory when trying to add a new WDDM Adapter to the list of valid adapters"); + free(driverStorePath); + return; + } + + pCtx->adapterList = newList; + + pCtx->adapterList[pCtx->adapterCount].hAdapter = pAdapterInfo->hAdapter; + pCtx->adapterList[pCtx->adapterCount].pDriverStorePath = driverStorePath; + pCtx->adapterList[pCtx->adapterCount].wddmVersion = wddmVersion; + pCtx->adapterCount++; + } + + log_infof("Adding new adapter via dxcore hAdapter:%x luid:%llx wddm version:%d", pAdapterInfo->hAdapter, *((unsigned long long*)&pAdapterInfo->AdapterLuid), wddmVersion); +} + +static int dxcore_enum_adapters3(struct dxcore_context* pCtx, struct dxcore_lib* pLib) +{ + struct dxcore_enumAdapters3 params = {0}; + unsigned int adapterIndex = 0; + + // Include compute-only in addition to display+compute adapters + params.Filter = ENUMADAPTER3_FILTER_COMPUTE_ONLY; + params.NumAdapters = 0; + params.pAdapters = NULL; + + if (pLib->pDxcoreEnumAdapters3(¶ms)) { + log_err("Failed to enumerate adapters via enumAdapers3"); + return 1; + } + + params.pAdapters = malloc(sizeof(struct dxcore_adapterInfo) * params.NumAdapters); + if (pLib->pDxcoreEnumAdapters3(¶ms)) { + free(params.pAdapters); + log_err("Failed to enumerate adapters via enumAdapers3"); + return 1; + } + + for (adapterIndex = 0; adapterIndex < params.NumAdapters; adapterIndex++) { + dxcore_add_adapter(pCtx, pLib, ¶ms.pAdapters[adapterIndex]); + } + + free(params.pAdapters); + return 0; +} + +static int dxcore_enum_adapters2(struct dxcore_context* pCtx, struct dxcore_lib* pLib) +{ + struct dxcore_enumAdapters2 params = {0}; + unsigned int adapterIndex = 0; + + params.NumAdapters = 0; + params.pAdapters = NULL; + + if (pLib->pDxcoreEnumAdapters2(¶ms)) { + log_err("Failed to enumerate adapters via enumAdapters2"); + return 1; + } + + params.pAdapters = malloc(sizeof(struct dxcore_adapterInfo) * params.NumAdapters); + if (pLib->pDxcoreEnumAdapters2(¶ms)) { + free(params.pAdapters); + log_err("Failed to enumerate adapters via enumAdapters2"); + return 1; + } + + for (adapterIndex = 0; adapterIndex < params.NumAdapters; adapterIndex++) { + dxcore_add_adapter(pCtx, pLib, ¶ms.pAdapters[adapterIndex]); + } + + free(params.pAdapters); + return 0; +} + +static void dxcore_enum_adapters(struct dxcore_context* pCtx, struct dxcore_lib* pLib) +{ + int status; + if (pLib->pDxcoreEnumAdapters3) { + status = dxcore_enum_adapters3(pCtx, pLib); + if (status == 0) { + return; + } + } + + // Fall back to EnumAdapters2 if the OS doesn't support EnumAdapters3 + if (pLib->pDxcoreEnumAdapters2) { + status = dxcore_enum_adapters2(pCtx, pLib); + if (status == 0) { + return; + } + } + log_err("Failed to enumerate adapters via dxcore"); +} + +int dxcore_init_context(struct dxcore_context* pCtx) +{ + struct dxcore_lib lib = {0}; + + pCtx->initialized = 0; + pCtx->adapterCount = 0; + pCtx->adapterList = NULL; + + lib.hDxcoreLib = dlopen("libdxcore.so", RTLD_LAZY); + if (!lib.hDxcoreLib) { + goto error; + } + + lib.pDxcoreEnumAdapters2 = (pfnDxcoreEnumAdapters2)dlsym(lib.hDxcoreLib, "D3DKMTEnumAdapters2"); + lib.pDxcoreEnumAdapters3 = (pfnDxcoreEnumAdapters3)dlsym(lib.hDxcoreLib, "D3DKMTEnumAdapters3"); + if (!lib.pDxcoreEnumAdapters2 && !lib.pDxcoreEnumAdapters3) { + log_err("dxcore library is present but the symbols D3DKMTEnumAdapters2 and D3DKMTEnumAdapters3 are missing"); + goto error; + } + + lib.pDxcoreQueryAdapterInfo = (pfnDxcoreQueryAdapterInfo)dlsym(lib.hDxcoreLib, "D3DKMTQueryAdapterInfo"); + if (!lib.pDxcoreQueryAdapterInfo) { + log_err("dxcore library is present but the symbol D3DKMTQueryAdapterInfo is missing"); + goto error; + } + + dxcore_enum_adapters(pCtx, &lib); + + log_info("dxcore layer initialized successfully"); + pCtx->initialized = 1; + + dlclose(lib.hDxcoreLib); + + return 0; + +error: + dxcore_deinit_context(pCtx); + + if (lib.hDxcoreLib) + dlclose(lib.hDxcoreLib); + + return (-1); +} + +static void dxcore_deinit_adapter(struct dxcore_adapter* pAdapter) +{ + if (!pAdapter) + return; + + free(pAdapter->pDriverStorePath); +} + +void dxcore_deinit_context(struct dxcore_context* pCtx) +{ + unsigned int adapterIndex = 0; + + if (!pCtx) + return; + + for (adapterIndex = 0; adapterIndex < pCtx->adapterCount; adapterIndex++) { + dxcore_deinit_adapter(&pCtx->adapterList[adapterIndex]); + } + + free(pCtx->adapterList); + + pCtx->initialized = 0; +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/dxcore.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/dxcore.go new file mode 100644 index 00000000..cbac0141 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/dxcore.go @@ -0,0 +1,61 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package dxcore + +/* +#cgo linux LDFLAGS: -Wl,--export-dynamic -Wl,--unresolved-symbols=ignore-in-object-files +#cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup + +#include +*/ +import "C" +import ( + "fmt" + "unsafe" +) + +type context C.struct_dxcore_context +type adapter C.struct_dxcore_adapter + +// initContext initializes the dxcore context and populates the list of adapters. +func initContext() (*context, error) { + cContext := C.struct_dxcore_context{} + if C.dxcore_init_context(&cContext) != 0 { + return nil, fmt.Errorf("failed to initialize dxcore context") + } + c := (*context)(&cContext) + return c, nil +} + +// deinitContext deinitializes the dxcore context and frees the list of adapters. +func (c context) deinitContext() { + cContext := C.struct_dxcore_context(c) + C.dxcore_deinit_context(&cContext) +} + +func (c context) getAdapterCount() int { + return int(c.adapterCount) +} + +func (c context) getAdapter(index int) adapter { + arrayPointer := (*[1 << 30]C.struct_dxcore_adapter)(unsafe.Pointer(c.adapterList)) + return adapter(arrayPointer[index]) +} + +func (a adapter) getDriverStorePath() string { + return C.GoString(a.pDriverStorePath) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/dxcore.h b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/dxcore.h new file mode 100644 index 00000000..9c044fee --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore/dxcore.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + */ + +#ifndef HEADER_DXCORE_H_ +#define HEADER_DXCORE_H_ + +#define MAX_DXCORE_DRIVERSTORE_LIBRAIRIES (16) + +struct dxcore_luid +{ + unsigned int lowPart; + int highPart; +}; + +struct dxcore_adapter +{ + unsigned int hAdapter; + unsigned int wddmVersion; + char* pDriverStorePath; + unsigned int driverStoreComponentCount; + const char* pDriverStoreComponents[MAX_DXCORE_DRIVERSTORE_LIBRAIRIES]; + struct dxcore_context *pContext; +}; + +struct dxcore_context +{ + unsigned int adapterCount; + struct dxcore_adapter *adapterList; + + int initialized; +}; + + + +int dxcore_init_context(struct dxcore_context* pDxcore_context); +void dxcore_deinit_context(struct dxcore_context* pDxcore_context); + +#endif // HEADER_DXCORE_H_ diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/device.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/device.go new file mode 100644 index 00000000..d04df153 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/device.go @@ -0,0 +1,61 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package edits + +import ( + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" +) + +type device discover.Device + +// toEdits converts a discovered device to CDI Container Edits. +func (d device) toEdits() (*cdi.ContainerEdits, error) { + deviceNode, err := d.toSpec() + if err != nil { + return nil, err + } + + e := cdi.ContainerEdits{ + ContainerEdits: &specs.ContainerEdits{ + DeviceNodes: []*specs.DeviceNode{deviceNode}, + }, + } + return &e, nil +} + +// toSpec converts a discovered Device to a CDI Spec Device. Note +// that missing info is filled in when edits are applied by querying the Device node. +func (d device) toSpec() (*specs.DeviceNode, error) { + // The HostPath field was added in the v0.5.0 CDI specification. + // The cdi package uses strict unmarshalling when loading specs from file causing failures for + // unexpected fields. + // Since the behaviour for HostPath == "" and HostPath == Path are equivalent, we clear HostPath + // if it is equal to Path to ensure compatibility with the widest range of specs. + hostPath := d.HostPath + if hostPath == d.Path { + hostPath = "" + } + s := specs.DeviceNode{ + HostPath: hostPath, + Path: d.Path, + } + + return &s, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/edits.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/edits.go new file mode 100644 index 00000000..4538ac31 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/edits.go @@ -0,0 +1,125 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package edits + +import ( + "fmt" + + ociSpecs "github.com/opencontainers/runtime-spec/specs-go" + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/oci" +) + +type edits struct { + cdi.ContainerEdits + logger logger.Interface +} + +// NewSpecEdits creates a SpecModifier that defines the required OCI spec edits (as CDI ContainerEdits) from the specified +// discoverer. +func NewSpecEdits(logger logger.Interface, d discover.Discover) (oci.SpecModifier, error) { + c, err := FromDiscoverer(d) + if err != nil { + return nil, fmt.Errorf("error constructing container edits: %v", err) + } + e := edits{ + ContainerEdits: *c, + logger: logger, + } + + return &e, nil +} + +// FromDiscoverer creates CDI container edits for the specified discoverer. +func FromDiscoverer(d discover.Discover) (*cdi.ContainerEdits, error) { + devices, err := d.Devices() + if err != nil { + return nil, fmt.Errorf("failed to discover devices: %v", err) + } + + envs, err := d.EnvVars() + if err != nil { + return nil, fmt.Errorf("failed to discover environment variables: %w", err) + } + + mounts, err := d.Mounts() + if err != nil { + return nil, fmt.Errorf("failed to discover mounts: %v", err) + } + + hooks, err := d.Hooks() + if err != nil { + return nil, fmt.Errorf("failed to discover hooks: %v", err) + } + + c := NewContainerEdits() + for _, d := range devices { + edits, err := device(d).toEdits() + if err != nil { + return nil, fmt.Errorf("failed to created container edits for device: %v", err) + } + c.Append(edits) + } + + for _, e := range envs { + c.Append(envvar(e).toEdits()) + } + + for _, m := range mounts { + c.Append(mount(m).toEdits()) + } + + for _, h := range hooks { + c.Append(hook(h).toEdits()) + } + + return c, nil +} + +// NewContainerEdits is a utility function to create a CDI ContainerEdits struct. +func NewContainerEdits() *cdi.ContainerEdits { + c := cdi.ContainerEdits{ + ContainerEdits: &specs.ContainerEdits{}, + } + return &c +} + +// Modify applies the defined edits to the incoming OCI spec +func (e *edits) Modify(spec *ociSpecs.Spec) error { + if e == nil || e.ContainerEdits.ContainerEdits == nil { + return nil + } + + e.logger.Info("Mounts:") + for _, mount := range e.Mounts { + e.logger.Infof("Mounting %v at %v", mount.HostPath, mount.ContainerPath) + } + e.logger.Infof("Devices:") + for _, device := range e.DeviceNodes { + e.logger.Infof("Injecting %v", device.Path) + } + e.logger.Infof("Hooks:") + for _, hook := range e.Hooks { + e.logger.Infof("Injecting %v %v", hook.Path, hook.Args) + } + + return e.Apply(spec) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/envvar.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/envvar.go new file mode 100644 index 00000000..359ce6b9 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/envvar.go @@ -0,0 +1,39 @@ +/** +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package edits + +import ( + "fmt" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" +) + +type envvar discover.EnvVar + +// toEdits converts a discovered envvar to CDI Container Edits. +func (d envvar) toEdits() *cdi.ContainerEdits { + e := cdi.ContainerEdits{ + ContainerEdits: &specs.ContainerEdits{ + Env: []string{fmt.Sprintf("%s=%s", d.Name, d.Value)}, + }, + } + return &e +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/hook.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/hook.go new file mode 100644 index 00000000..ca5466d4 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/hook.go @@ -0,0 +1,49 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package edits + +import ( + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" +) + +type hook discover.Hook + +// toEdits converts a discovered hook to CDI Container Edits. +func (d hook) toEdits() *cdi.ContainerEdits { + e := cdi.ContainerEdits{ + ContainerEdits: &specs.ContainerEdits{ + Hooks: []*specs.Hook{d.toSpec()}, + }, + } + return &e +} + +// toSpec converts a discovered Hook to a CDI Spec Hook. Note +// that missing info is filled in when edits are applied by querying the Hook node. +func (d hook) toSpec() *specs.Hook { + s := specs.Hook{ + HookName: d.Lifecycle, + Path: d.Path, + Args: d.Args, + Env: d.Env, + } + + return &s +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/mount.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/mount.go new file mode 100644 index 00000000..a588ec04 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/edits/mount.go @@ -0,0 +1,48 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package edits + +import ( + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" +) + +type mount discover.Mount + +// toEdits converts a discovered mount to CDI Container Edits. +func (d mount) toEdits() *cdi.ContainerEdits { + e := cdi.ContainerEdits{ + ContainerEdits: &specs.ContainerEdits{ + Mounts: []*specs.Mount{d.toSpec()}, + }, + } + return &e +} + +// toSpec converts a discovered Mount to a CDI Spec Mount. Note +// that missing info is filled in when edits are applied by querying the Mount node. +func (d mount) toSpec() *specs.Mount { + s := specs.Mount{ + HostPath: d.HostPath, + ContainerPath: d.Path, + Options: d.Options, + } + + return &s +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/drm/drm_devices.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/drm/drm_devices.go new file mode 100644 index 00000000..3b8204bc --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/drm/drm_devices.go @@ -0,0 +1,39 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package drm + +import ( + "fmt" + "path/filepath" +) + +// GetDeviceNodesByBusID returns the DRM devices associated with the specified PCI bus ID +func GetDeviceNodesByBusID(busID string) ([]string, error) { + drmRoot := filepath.Join("/sys/bus/pci/devices", busID, "drm") + matches, err := filepath.Glob(fmt.Sprintf("%s/*", drmRoot)) + if err != nil { + return nil, err + } + + var drmDeviceNodes []string + for _, m := range matches { + drmDeviceNode := filepath.Join("/dev/dri", filepath.Base(m)) + drmDeviceNodes = append(drmDeviceNodes, drmDeviceNode) + } + + return drmDeviceNodes, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices/builder.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices/builder.go new file mode 100644 index 00000000..6da9a90d --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices/builder.go @@ -0,0 +1,62 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package devices + +type builder struct { + asMap devices + filter func(string) bool +} + +// New creates a new devices struct with the specified options. +func New(opts ...Option) Devices { + b := &builder{} + for _, opt := range opts { + opt(b) + } + + if b.filter == nil { + b.filter = func(string) bool { return false } + } + + devices := make(devices) + for k, v := range b.asMap { + if b.filter(string(k)) { + continue + } + devices[k] = v + } + return devices +} + +type Option func(*builder) + +// WithDeviceToMajor specifies an explicit device name to major number map. +func WithDeviceToMajor(deviceToMajor map[string]int) Option { + return func(b *builder) { + b.asMap = make(devices) + for name, major := range deviceToMajor { + b.asMap[Name(name)] = Major(major) + } + } +} + +// WithFilter specifies a filter to exclude devices. +func WithFilter(filter func(string) bool) Option { + return func(b *builder) { + b.filter = filter + } +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices/devices.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices/devices.go new file mode 100644 index 00000000..534a4afd --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices/devices.go @@ -0,0 +1,158 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package devices + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "strings" +) + +// Device major numbers and device names for NVIDIA devices +const ( + NVIDIAUVMMinor = 0 + NVIDIAUVMToolsMinor = 1 + NVIDIACTLMinor = 255 + NVIDIAModesetMinor = 254 + + NVIDIAFrontend = Name("nvidia-frontend") + NVIDIAGPU = Name("nvidia") + NVIDIACaps = Name("nvidia-caps") + NVIDIAUVM = Name("nvidia-uvm") + + procDevicesPath = "/proc/devices" + nvidiaDevicePrefix = "nvidia" +) + +// Name represents the name of a device as specified under /proc/devices +type Name string + +// Major represents a device major as specified under /proc/devices +type Major int + +// Devices represents the set of devices under /proc/devices +// +//go:generate moq -rm -fmt=goimports -stub -out devices_mock.go . Devices +type Devices interface { + Exists(Name) bool + Get(Name) (Major, bool) + Count() int +} + +type devices map[Name]Major + +var _ Devices = devices(nil) + +// Count returns the number of devices defined. +func (d devices) Count() int { + return len(d) +} + +// Exists checks if a Device with a given name exists or not +func (d devices) Exists(name Name) bool { + _, exists := d.Get(name) + return exists +} + +// Get a Device from Devices. It also has fallback logic to ensure device name changes in /proc/devices are handled +// For e.g:- For GPU drivers 550.40.x or greater, the gpu device has been renamed from "nvidia-frontend" to "nvidia". +func (d devices) Get(name Name) (Major, bool) { + for _, n := range name.getWithFallback() { + device, exists := d[n] + if exists { + return device, true + } + } + return 0, false +} + +// getWithFallback returns a prioritised list of device names for a specific name. +// This allows multiple names to be associated with a single name to support various driver versions. +func (n Name) getWithFallback() []Name { + if n == NVIDIAGPU || n == NVIDIAFrontend { + return []Name{NVIDIAGPU, NVIDIAFrontend} + } + return []Name{n} +} + +// GetNVIDIADevices returns the set of NVIDIA Devices on the machine +func GetNVIDIADevices() (Devices, error) { + return nvidiaDevices(procDevicesPath) +} + +// nvidiaDevices returns the set of NVIDIA Devices from the specified devices file. +// This is useful for testing since we may be testing on a system where `/proc/devices` does +// contain a reference to NVIDIA devices. +func nvidiaDevices(devicesPath string) (Devices, error) { + devicesFile, err := os.Open(devicesPath) + if os.IsNotExist(err) { + return nil, nil + } + if err != nil { + return nil, fmt.Errorf("error opening devices file: %v", err) + } + defer devicesFile.Close() + + return nvidiaDeviceFrom(devicesFile) +} + +var errNoNvidiaDevices = errors.New("no NVIDIA devices found") + +func nvidiaDeviceFrom(reader io.Reader) (Devices, error) { + allDevices := devicesFrom(reader) + + nvidiaDevices := New( + WithDeviceToMajor(allDevices), + WithFilter(func(n string) bool { + return !strings.HasPrefix(n, nvidiaDevicePrefix) + }), + ) + if nvidiaDevices.Count() == 0 { + return nil, errNoNvidiaDevices + } + return nvidiaDevices, nil +} + +func devicesFrom(reader io.Reader) map[string]int { + allDevices := make(map[string]int) + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + device, major, err := processProcDeviceLine(scanner.Text()) + if err != nil { + continue + } + allDevices[device] = major + } + return allDevices +} + +func processProcDeviceLine(line string) (string, int, error) { + trimmed := strings.TrimSpace(line) + + var name string + var major int + + n, _ := fmt.Sscanf(trimmed, "%d %s", &major, &name) + if n == 2 { + return name, major, nil + } + + return "", 0, fmt.Errorf("unparsable line: %v", line) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices/devices_mock.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices/devices_mock.go new file mode 100644 index 00000000..8f32cd8b --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices/devices_mock.go @@ -0,0 +1,165 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package devices + +import ( + "sync" +) + +// Ensure, that DevicesMock does implement Devices. +// If this is not the case, regenerate this file with moq. +var _ Devices = &DevicesMock{} + +// DevicesMock is a mock implementation of Devices. +// +// func TestSomethingThatUsesDevices(t *testing.T) { +// +// // make and configure a mocked Devices +// mockedDevices := &DevicesMock{ +// CountFunc: func() int { +// panic("mock out the Count method") +// }, +// ExistsFunc: func(name Name) bool { +// panic("mock out the Exists method") +// }, +// GetFunc: func(name Name) (Major, bool) { +// panic("mock out the Get method") +// }, +// } +// +// // use mockedDevices in code that requires Devices +// // and then make assertions. +// +// } +type DevicesMock struct { + // CountFunc mocks the Count method. + CountFunc func() int + + // ExistsFunc mocks the Exists method. + ExistsFunc func(name Name) bool + + // GetFunc mocks the Get method. + GetFunc func(name Name) (Major, bool) + + // calls tracks calls to the methods. + calls struct { + // Count holds details about calls to the Count method. + Count []struct { + } + // Exists holds details about calls to the Exists method. + Exists []struct { + // Name is the name argument value. + Name Name + } + // Get holds details about calls to the Get method. + Get []struct { + // Name is the name argument value. + Name Name + } + } + lockCount sync.RWMutex + lockExists sync.RWMutex + lockGet sync.RWMutex +} + +// Count calls CountFunc. +func (mock *DevicesMock) Count() int { + callInfo := struct { + }{} + mock.lockCount.Lock() + mock.calls.Count = append(mock.calls.Count, callInfo) + mock.lockCount.Unlock() + if mock.CountFunc == nil { + var ( + nOut int + ) + return nOut + } + return mock.CountFunc() +} + +// CountCalls gets all the calls that were made to Count. +// Check the length with: +// +// len(mockedDevices.CountCalls()) +func (mock *DevicesMock) CountCalls() []struct { +} { + var calls []struct { + } + mock.lockCount.RLock() + calls = mock.calls.Count + mock.lockCount.RUnlock() + return calls +} + +// Exists calls ExistsFunc. +func (mock *DevicesMock) Exists(name Name) bool { + callInfo := struct { + Name Name + }{ + Name: name, + } + mock.lockExists.Lock() + mock.calls.Exists = append(mock.calls.Exists, callInfo) + mock.lockExists.Unlock() + if mock.ExistsFunc == nil { + var ( + bOut bool + ) + return bOut + } + return mock.ExistsFunc(name) +} + +// ExistsCalls gets all the calls that were made to Exists. +// Check the length with: +// +// len(mockedDevices.ExistsCalls()) +func (mock *DevicesMock) ExistsCalls() []struct { + Name Name +} { + var calls []struct { + Name Name + } + mock.lockExists.RLock() + calls = mock.calls.Exists + mock.lockExists.RUnlock() + return calls +} + +// Get calls GetFunc. +func (mock *DevicesMock) Get(name Name) (Major, bool) { + callInfo := struct { + Name Name + }{ + Name: name, + } + mock.lockGet.Lock() + mock.calls.Get = append(mock.calls.Get, callInfo) + mock.lockGet.Unlock() + if mock.GetFunc == nil { + var ( + majorOut Major + bOut bool + ) + return majorOut, bOut + } + return mock.GetFunc(name) +} + +// GetCalls gets all the calls that were made to Get. +// Check the length with: +// +// len(mockedDevices.GetCalls()) +func (mock *DevicesMock) GetCalls() []struct { + Name Name +} { + var calls []struct { + Name Name + } + mock.lockGet.RLock() + calls = mock.calls.Get + mock.lockGet.RUnlock() + return calls +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/information_files.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/information_files.go new file mode 100644 index 00000000..f84b76a6 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/information_files.go @@ -0,0 +1,89 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package proc + +import ( + "bufio" + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +// GPUInfoField represents the field name for information specified in a GPU's information file +type GPUInfoField string + +// The following constants define the fields of interest from the GPU information file +const ( + GPUInfoModel = GPUInfoField("Model") + GPUInfoGPUUUID = GPUInfoField("GPU UUID") + GPUInfoBusLocation = GPUInfoField("Bus Location") + GPUInfoDeviceMinor = GPUInfoField("Device Minor") +) + +// GPUInfo stores the information for a GPU as determined from its associated information file +type GPUInfo map[GPUInfoField]string + +// GetInformationFilePaths returns the list of information files associated with NVIDIA GPUs. +func GetInformationFilePaths(root string) ([]string, error) { + return filepath.Glob(filepath.Join(root, "/proc/driver/nvidia/gpus/*/information")) +} + +// ParseGPUInformationFile parses the specified GPU information file and constructs a GPUInfo structure +func ParseGPUInformationFile(path string) (GPUInfo, error) { + infoFile, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("failed to open %v: %v", path, err) + } + defer infoFile.Close() + + return gpuInfoFrom(infoFile), nil +} + +// gpuInfoFrom parses a GPUInfo struct from the specified reader +// An information file has the following structure: +// $ cat /proc/driver/nvidia/gpus/0000\:06\:00.0/information +// Model: Tesla V100-SXM2-16GB +// IRQ: 408 +// GPU UUID: GPU-edfee158-11c1-52b8-0517-92f30e7fac88 +// Video BIOS: 88.00.41.00.01 +// Bus Type: PCIe +// DMA Size: 47 bits +// DMA Mask: 0x7fffffffffff +// Bus Location: 0000:06:00.0 +// Device Minor: 0 +// GPU Excluded: No +func gpuInfoFrom(reader io.Reader) GPUInfo { + info := make(GPUInfo) + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + line := scanner.Text() + + parts := strings.SplitN(line, ":", 2) + if len(parts) != 2 { + continue + } + + field := GPUInfoField(parts[0]) + value := strings.TrimSpace(parts[1]) + + info[field] = value + } + + return info +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache/ldcache.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache/ldcache.go new file mode 100644 index 00000000..83179256 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache/ldcache.go @@ -0,0 +1,266 @@ +/* +# Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +// Adapted from https://github.com/rai-project/ldcache + +package ldcache + +import ( + "bytes" + "encoding/binary" + "errors" + "os" + "path/filepath" + "syscall" + "unsafe" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +const ldcachePath = "/etc/ld.so.cache" + +const ( + magicString1 = "ld.so-1.7.0" + magicString2 = "glibc-ld.so.cache" + magicVersion = "1.1" +) + +const ( + flagTypeMask = 0x00ff + flagTypeELF = 0x0001 + + flagArchMask = 0xff00 + flagArchI386 = 0x0000 + flagArchX8664 = 0x0300 + flagArchX32 = 0x0800 + flagArchPpc64le = 0x0500 + + // flagArch_ARM_LIBHF is the flag value for 32-bit ARM libs using hard-float. + flagArch_ARM_LIBHF = 0x0900 + // flagArch_AARCH64_LIB64 is the flag value for 64-bit ARM libs. + flagArch_AARCH64_LIB64 = 0x0a00 +) + +var errInvalidCache = errors.New("invalid ld.so.cache file") + +type header1 struct { + Magic [len(magicString1) + 1]byte // include null delimiter + NLibs uint32 +} + +type entry1 struct { + Flags int32 + Key, Value uint32 +} + +type header2 struct { + Magic [len(magicString2)]byte + Version [len(magicVersion)]byte + NLibs uint32 + TableSize uint32 + _ [3]uint32 // unused + _ uint64 // force 8 byte alignment +} + +type entry2 struct { + Flags int32 + Key, Value uint32 + OSVersion uint32 + HWCap uint64 +} + +// LDCache represents the interface for performing lookups into the LDCache +// +//go:generate moq -rm -fmt=goimports -out ldcache_mock.go . LDCache +type LDCache interface { + List() ([]string, []string) +} + +type ldcache struct { + *bytes.Reader + + data, libs []byte + header header2 + entries []entry2 + + root string + logger logger.Interface +} + +// New creates a new LDCache with the specified logger and root. +func New(logger logger.Interface, root string) (LDCache, error) { + path := filepath.Join(root, ldcachePath) + + logger.Debugf("Opening ld.conf at %v", path) + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return nil, err + } + d, err := syscall.Mmap(int(f.Fd()), 0, int(fi.Size()), + syscall.PROT_READ, syscall.MAP_PRIVATE) + if err != nil { + return nil, err + } + + cache := &ldcache{ + data: d, + Reader: bytes.NewReader(d), + root: root, + logger: logger, + } + return cache, cache.parse() +} + +func (c *ldcache) Close() error { + return syscall.Munmap(c.data) +} + +func (c *ldcache) Magic() string { + return string(c.header.Magic[:]) +} + +func (c *ldcache) Version() string { + return string(c.header.Version[:]) +} + +func strn(b []byte, n int) string { + return string(b[:n]) +} + +func (c *ldcache) parse() error { + var header header1 + + // Check for the old format (< glibc-2.2) + if c.Len() <= int(unsafe.Sizeof(header)) { + return errInvalidCache + } + if strn(c.data, len(magicString1)) == magicString1 { + if err := binary.Read(c, binary.LittleEndian, &header); err != nil { + return err + } + n := int64(header.NLibs) * int64(unsafe.Sizeof(entry1{})) + offset, err := c.Seek(n, 1) // skip old entries + if err != nil { + return err + } + n = (-offset) & int64(unsafe.Alignof(c.header)-1) + _, err = c.Seek(n, 1) // skip padding + if err != nil { + return err + } + } + + c.libs = c.data[c.Size()-int64(c.Len()):] // kv offsets start here + if err := binary.Read(c, binary.LittleEndian, &c.header); err != nil { + return err + } + if c.Magic() != magicString2 || c.Version() != magicVersion { + return errInvalidCache + } + c.entries = make([]entry2, c.header.NLibs) + if err := binary.Read(c, binary.LittleEndian, &c.entries); err != nil { + return err + } + return nil +} + +type entry struct { + libname string + bits int + value string +} + +// getEntries returns the entires of the ldcache in a go-friendly struct. +func (c *ldcache) getEntries() []entry { + var entries []entry + for _, e := range c.entries { + bits := 0 + if ((e.Flags & flagTypeMask) & flagTypeELF) == 0 { + continue + } + switch e.Flags & flagArchMask { + case flagArchX8664: + fallthrough + case flagArch_AARCH64_LIB64: + fallthrough + case flagArchPpc64le: + bits = 64 + case flagArchX32: + fallthrough + case flagArch_ARM_LIBHF: + fallthrough + case flagArchI386: + bits = 32 + default: + continue + } + if e.Key > uint32(len(c.libs)) || e.Value > uint32(len(c.libs)) { + continue + } + lib := bytesToString(c.libs[e.Key:]) + if lib == "" { + c.logger.Debugf("Skipping invalid lib") + continue + } + value := bytesToString(c.libs[e.Value:]) + if value == "" { + c.logger.Debugf("Skipping invalid value for lib %v", lib) + continue + } + e := entry{ + libname: lib, + bits: bits, + value: value, + } + entries = append(entries, e) + } + return entries +} + +// List creates a list of libraries in the ldcache. +// The 32-bit and 64-bit libraries are returned separately. +func (c *ldcache) List() ([]string, []string) { + paths := make(map[int][]string) + processed := make(map[string]bool) + + for _, e := range c.getEntries() { + path := filepath.Join(c.root, e.value) + if processed[path] { + continue + } + paths[e.bits] = append(paths[e.bits], path) + processed[path] = true + } + + return paths[32], paths[64] +} + +// bytesToString converts a byte slice to a string. +// This assumes that the byte slice is null-terminated +func bytesToString(value []byte) string { + n := bytes.IndexByte(value, 0) + if n < 0 { + return "" + } + + return strn(value, n) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache/ldcache_mock.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache/ldcache_mock.go new file mode 100644 index 00000000..5aa53235 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache/ldcache_mock.go @@ -0,0 +1,67 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package ldcache + +import ( + "sync" +) + +// Ensure, that LDCacheMock does implement LDCache. +// If this is not the case, regenerate this file with moq. +var _ LDCache = &LDCacheMock{} + +// LDCacheMock is a mock implementation of LDCache. +// +// func TestSomethingThatUsesLDCache(t *testing.T) { +// +// // make and configure a mocked LDCache +// mockedLDCache := &LDCacheMock{ +// ListFunc: func() ([]string, []string) { +// panic("mock out the List method") +// }, +// } +// +// // use mockedLDCache in code that requires LDCache +// // and then make assertions. +// +// } +type LDCacheMock struct { + // ListFunc mocks the List method. + ListFunc func() ([]string, []string) + + // calls tracks calls to the methods. + calls struct { + // List holds details about calls to the List method. + List []struct { + } + } + lockList sync.RWMutex +} + +// List calls ListFunc. +func (mock *LDCacheMock) List() ([]string, []string) { + if mock.ListFunc == nil { + panic("LDCacheMock.ListFunc: method is nil but LDCache.List was just called") + } + callInfo := struct { + }{} + mock.lockList.Lock() + mock.calls.List = append(mock.calls.List, callInfo) + mock.lockList.Unlock() + return mock.ListFunc() +} + +// ListCalls gets all the calls that were made to List. +// Check the length with: +// +// len(mockedLDCache.ListCalls()) +func (mock *LDCacheMock) ListCalls() []struct { +} { + var calls []struct { + } + mock.lockList.RLock() + calls = mock.calls.List + mock.lockList.RUnlock() + return calls +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/logger/api.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/logger/api.go new file mode 100644 index 00000000..750c64c6 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/logger/api.go @@ -0,0 +1,28 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package logger + +// Interface defines the API for the logger package +type Interface interface { + Debugf(string, ...interface{}) + Errorf(string, ...interface{}) + Info(...interface{}) + Infof(string, ...interface{}) + Warning(...interface{}) + Warningf(string, ...interface{}) + Tracef(string, ...interface{}) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/logger/lib.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/logger/lib.go new file mode 100644 index 00000000..ddb227bf --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/logger/lib.go @@ -0,0 +1,50 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package logger + +import "github.com/sirupsen/logrus" + +// New returns a new logger +func New() Interface { + return logrus.StandardLogger() +} + +// NullLogger is a logger that does nothing +type NullLogger struct{} + +var _ Interface = (*NullLogger)(nil) + +// Debugf is a no-op for the null logger +func (l *NullLogger) Debugf(string, ...interface{}) {} + +// Errorf is a no-op for the null logger +func (l *NullLogger) Errorf(string, ...interface{}) {} + +// Info is a no-op for the null logger +func (l *NullLogger) Info(...interface{}) {} + +// Infof is a no-op for the null logger +func (l *NullLogger) Infof(string, ...interface{}) {} + +// Warning is a no-op for the null logger +func (l *NullLogger) Warning(...interface{}) {} + +// Warningf is a no-op for the null logger +func (l *NullLogger) Warningf(string, ...interface{}) {} + +// Tracef is a no-op for the null logger +func (l *NullLogger) Tracef(string, ...interface{}) {} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/device.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/device.go new file mode 100644 index 00000000..e4fbe330 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/device.go @@ -0,0 +1,56 @@ +/** +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package lookup + +import ( + "fmt" + "os" +) + +const ( + devRoot = "/dev" +) + +// NewCharDeviceLocator creates a Locator that can be used to find char devices at the specified root. A logger is +// also specified. +func NewCharDeviceLocator(opts ...Option) Locator { + filter := assertCharDevice + // TODO: We should have a better way to inject this logic than this envvar. + if os.Getenv("__NVCT_TESTING_DEVICES_ARE_FILES") == "true" { + filter = assertFile + } + + opts = append(opts, + WithSearchPaths("", devRoot), + WithFilter(filter), + ) + return NewFileLocator( + opts..., + ) +} + +// assertCharDevice checks whether the specified path is a char device and returns an error if this is not the case. +func assertCharDevice(filename string) error { + info, err := os.Lstat(filename) + if err != nil { + return fmt.Errorf("error getting info: %v", err) + } + if info.Mode()&os.ModeCharDevice == 0 { + return fmt.Errorf("%v is not a char device", filename) + } + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/dir.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/dir.go new file mode 100644 index 00000000..edf42b56 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/dir.go @@ -0,0 +1,46 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package lookup + +import ( + "fmt" + "os" +) + +// NewDirectoryLocator creates a Locator that can be used to find directories at the specified root. +func NewDirectoryLocator(opts ...Option) Locator { + return NewFileLocator( + append( + opts, + WithFilter(assertDirectory), + )..., + ) +} + +// assertDirectory checks wither the specified path is a directory. +func assertDirectory(filename string) error { + info, err := os.Stat(filename) + if err != nil { + return fmt.Errorf("error getting info for %v: %v", filename, err) + } + + if !info.IsDir() { + return fmt.Errorf("specified path '%v' is not a directory", filename) + } + + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/executable.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/executable.go new file mode 100644 index 00000000..b94e850a --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/executable.go @@ -0,0 +1,87 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package lookup + +import ( + "fmt" + "os" + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +type executable struct { + file +} + +// NewExecutableLocator creates a locator to fine executable files in the path. A logger can also be specified. +func NewExecutableLocator(logger logger.Interface, root string) Locator { + paths := GetPaths(root) + + return newExecutableLocator(logger, root, paths...) +} + +func newExecutableLocator(logger logger.Interface, root string, paths ...string) *executable { + f := newFileLocator( + WithLogger(logger), + WithRoot(root), + WithSearchPaths(paths...), + WithFilter(assertExecutable), + WithCount(1), + ) + + l := executable{ + file: *f, + } + + return &l +} + +var _ Locator = (*executable)(nil) + +// Locate finds executable files with the specified pattern in the path. +// If a relative or absolute path is specified, the prefix paths are not considered. +func (p executable) Locate(pattern string) ([]string, error) { + // For absolute paths we ensure that it is executable + if strings.Contains(pattern, "/") { + err := assertExecutable(pattern) + if err != nil { + return nil, fmt.Errorf("absolute path %v is not an executable file: %v", pattern, err) + } + return []string{pattern}, nil + } + + return p.file.Locate(pattern) +} + +// assertExecutable checks whether the specified path is an execuable file. +func assertExecutable(filename string) error { + err := assertFile(filename) + if err != nil { + return err + } + info, err := os.Stat(filename) + if err != nil { + return err + } + + if info.Mode()&0111 == 0 { + return fmt.Errorf("specified file '%v' is not executable", filename) + } + + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/file.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/file.go new file mode 100644 index 00000000..8f330273 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/file.go @@ -0,0 +1,205 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package lookup + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +// file can be used to locate file (or file-like elements) at a specified set of +// prefixes. The validity of a file is determined by a filter function. +type file struct { + builder + prefixes []string +} + +// builder defines the builder for a file locator. +type builder struct { + logger logger.Interface + root string + searchPaths []string + filter func(string) error + count int + isOptional bool +} + +// Option defines a function for passing builder to the NewFileLocator() call +type Option func(*builder) + +// WithRoot sets the root for the file locator +func WithRoot(root string) Option { + return func(f *builder) { + f.root = root + } +} + +// WithLogger sets the logger for the file locator +func WithLogger(logger logger.Interface) Option { + return func(f *builder) { + f.logger = logger + } +} + +// WithSearchPaths sets the search paths for the file locator. +func WithSearchPaths(paths ...string) Option { + return func(f *builder) { + f.searchPaths = paths + } +} + +// WithFilter sets the filter for the file locator +// The filter is called for each candidate file and candidates that return nil are considered. +func WithFilter(assert func(string) error) Option { + return func(f *builder) { + f.filter = assert + } +} + +// WithCount sets the maximum number of candidates to discover +func WithCount(count int) Option { + return func(f *builder) { + f.count = count + } +} + +// WithOptional sets the optional flag for the file locator +// If the optional flag is set, the locator will not return an error if the file is not found. +func WithOptional(optional bool) Option { + return func(f *builder) { + f.isOptional = optional + } +} + +func newBuilder(opts ...Option) *builder { + o := &builder{} + for _, opt := range opts { + opt(o) + } + if o.logger == nil { + o.logger = logger.New() + } + if o.filter == nil { + o.filter = assertFile + } + return o +} + +func (o builder) build() *file { + f := file{ + builder: o, + // Since the `Locate` implementations rely on the root already being specified we update + // the prefixes to include the root. + prefixes: getSearchPrefixes(o.root, o.searchPaths...), + } + return &f +} + +// NewFileLocator creates a Locator that can be used to find files with the specified builder. +func NewFileLocator(opts ...Option) Locator { + return newFileLocator(opts...) +} + +func newFileLocator(opts ...Option) *file { + return newBuilder(opts...).build() +} + +// getSearchPrefixes generates a list of unique paths to be searched by a file locator. +// +// For each of the unique prefixes

specified, the path

is searched, where is the +// specified root. If no prefixes are specified, is returned as the only search prefix. +// +// Note that an empty root is equivalent to searching relative to the current working directory, and +// if the root filesystem should be searched instead, root should be specified as "/" explicitly. +// +// Also, a prefix of "" forces the root to be included in returned set of paths. This means that if +// the root in addition to another prefix must be searched the function should be called with: +// +// getSearchPrefixes("/root", "", "another/path") +// +// and will result in the search paths []{"/root", "/root/another/path"} being returned. +func getSearchPrefixes(root string, prefixes ...string) []string { + seen := make(map[string]bool) + var uniquePrefixes []string + for _, p := range prefixes { + if seen[p] { + continue + } + seen[p] = true + uniquePrefixes = append(uniquePrefixes, filepath.Join(root, p)) + } + + if len(uniquePrefixes) == 0 { + uniquePrefixes = append(uniquePrefixes, root) + } + + return uniquePrefixes +} + +var _ Locator = (*file)(nil) + +// Locate attempts to find files with names matching the specified pattern. +// All prefixes are searched and any matching candidates are returned. If no matches are found, an error is returned. +func (p file) Locate(pattern string) ([]string, error) { + var filenames []string + + p.logger.Debugf("Locating %q in %v", pattern, p.prefixes) +visit: + for _, prefix := range p.prefixes { + pathPattern := filepath.Join(prefix, pattern) + candidates, err := filepath.Glob(pathPattern) + if err != nil { + p.logger.Debugf("Checking pattern '%v' failed: %v", pathPattern, err) + } + + for _, candidate := range candidates { + p.logger.Debugf("Checking candidate '%v'", candidate) + err := p.filter(candidate) + if err != nil { + p.logger.Debugf("Candidate '%v' does not meet requirements: %v", candidate, err) + continue + } + filenames = append(filenames, candidate) + if p.count > 0 && len(filenames) == p.count { + p.logger.Debugf("Found %d candidates; ignoring further candidates", len(filenames)) + break visit + } + } + } + + if !p.isOptional && len(filenames) == 0 { + return nil, fmt.Errorf("pattern %v %w", pattern, ErrNotFound) + } + return filenames, nil +} + +// assertFile checks whether the specified path is a regular file +func assertFile(filename string) error { + info, err := os.Stat(filename) + if err != nil { + return fmt.Errorf("error getting info for %v: %v", filename, err) + } + + if info.IsDir() { + return fmt.Errorf("specified path '%v' is a directory", filename) + } + + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/ldcache.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/ldcache.go new file mode 100644 index 00000000..677dafaa --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/ldcache.go @@ -0,0 +1,118 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package lookup + +import ( + "fmt" + "path/filepath" + "slices" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache" +) + +type ldcacheLocator struct { + *builder + resolvesTo map[string]string +} + +var _ Locator = (*ldcacheLocator)(nil) + +func NewLdcacheLocator(opts ...Option) Locator { + b := newBuilder(opts...) + + cache, err := ldcache.New(b.logger, b.root) + if err != nil { + b.logger.Warningf("Failed to load ldcache: %v", err) + if b.isOptional { + return &null{} + } + return ¬Found{} + } + + chain := NewSymlinkChainLocator(WithOptional(true)) + + resolvesTo := make(map[string]string) + _, libs64 := cache.List() + for _, library := range libs64 { + if _, processed := resolvesTo[library]; processed { + continue + } + candidates, err := chain.Locate(library) + if err != nil { + b.logger.Errorf("error processing library %s from ldcache: %v", library, err) + continue + } + + if len(candidates) == 0 { + resolvesTo[library] = library + continue + } + + // candidates represents a symlink chain. + // The first element represents the start of the chain and the last + // element the final target. + target := candidates[len(candidates)-1] + for _, candidate := range candidates { + resolvesTo[candidate] = target + } + } + + return &ldcacheLocator{ + builder: b, + resolvesTo: resolvesTo, + } +} + +// Locate finds the specified libraryname. +// If the input is a library name, the ldcache is searched otherwise the +// provided path is resolved as a symlink. +func (l ldcacheLocator) Locate(libname string) ([]string, error) { + var matcher func(string, string) bool + + if filepath.IsAbs(libname) { + matcher = func(p string, c string) bool { + m, _ := filepath.Match(filepath.Join(l.root, p), c) + return m + } + } else { + matcher = func(p string, c string) bool { + m, _ := filepath.Match(p, filepath.Base(c)) + return m + } + } + + var matches []string + seen := make(map[string]bool) + for name, target := range l.resolvesTo { + if !matcher(libname, name) { + continue + } + if seen[target] { + continue + } + seen[target] = true + matches = append(matches, target) + } + + slices.Sort(matches) + + if len(matches) == 0 && !l.isOptional { + return nil, fmt.Errorf("%s: %w", libname, ErrNotFound) + } + + return matches, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/library.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/library.go new file mode 100644 index 00000000..6c403d08 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/library.go @@ -0,0 +1,55 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package lookup + +// NewLibraryLocator creates a library locator using the specified options. +func NewLibraryLocator(opts ...Option) Locator { + b := newBuilder(opts...) + + // If search paths are already specified, we return a locator for the specified search paths. + if len(b.searchPaths) > 0 { + return NewSymlinkLocator( + WithLogger(b.logger), + WithSearchPaths(b.searchPaths...), + WithRoot("/"), + ) + } + + opts = append(opts, + WithSearchPaths([]string{ + "/", + "/usr/lib64", + "/usr/lib/x86_64-linux-gnu", + "/usr/lib/aarch64-linux-gnu", + "/usr/lib/x86_64-linux-gnu/nvidia/current", + "/usr/lib/aarch64-linux-gnu/nvidia/current", + "/lib64", + "/lib/x86_64-linux-gnu", + "/lib/aarch64-linux-gnu", + "/lib/x86_64-linux-gnu/nvidia/current", + "/lib/aarch64-linux-gnu/nvidia/current", + }...), + ) + // We construct a symlink locator for expected library locations. + symlinkLocator := NewSymlinkLocator(opts...) + + l := First( + symlinkLocator, + NewLdcacheLocator(opts...), + ) + return l +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/locator.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/locator.go new file mode 100644 index 00000000..9906327c --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/locator.go @@ -0,0 +1,29 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package lookup + +import "errors" + +//go:generate moq -rm -fmt=goimports -stub -out locator_mock.go . Locator + +// Locator defines the interface for locating files on a system. +type Locator interface { + Locate(string) ([]string, error) +} + +// ErrNotFound indicates that a specified pattern or file could not be found. +var ErrNotFound = errors.New("not found") diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/locator_mock.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/locator_mock.go new file mode 100644 index 00000000..10a73aa3 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/locator_mock.go @@ -0,0 +1,78 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package lookup + +import ( + "sync" +) + +// Ensure, that LocatorMock does implement Locator. +// If this is not the case, regenerate this file with moq. +var _ Locator = &LocatorMock{} + +// LocatorMock is a mock implementation of Locator. +// +// func TestSomethingThatUsesLocator(t *testing.T) { +// +// // make and configure a mocked Locator +// mockedLocator := &LocatorMock{ +// LocateFunc: func(s string) ([]string, error) { +// panic("mock out the Locate method") +// }, +// } +// +// // use mockedLocator in code that requires Locator +// // and then make assertions. +// +// } +type LocatorMock struct { + // LocateFunc mocks the Locate method. + LocateFunc func(s string) ([]string, error) + + // calls tracks calls to the methods. + calls struct { + // Locate holds details about calls to the Locate method. + Locate []struct { + // S is the s argument value. + S string + } + } + lockLocate sync.RWMutex +} + +// Locate calls LocateFunc. +func (mock *LocatorMock) Locate(s string) ([]string, error) { + callInfo := struct { + S string + }{ + S: s, + } + mock.lockLocate.Lock() + mock.calls.Locate = append(mock.calls.Locate, callInfo) + mock.lockLocate.Unlock() + if mock.LocateFunc == nil { + var ( + stringsOut []string + errOut error + ) + return stringsOut, errOut + } + return mock.LocateFunc(s) +} + +// LocateCalls gets all the calls that were made to Locate. +// Check the length with: +// +// len(mockedLocator.LocateCalls()) +func (mock *LocatorMock) LocateCalls() []struct { + S string +} { + var calls []struct { + S string + } + mock.lockLocate.RLock() + calls = mock.calls.Locate + mock.lockLocate.RUnlock() + return calls +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/merge.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/merge.go new file mode 100644 index 00000000..fa20b512 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/merge.go @@ -0,0 +1,53 @@ +/** +# Copyright 2023 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package lookup + +import "errors" + +type first []Locator + +// First returns a locator that returns the first non-empty match +func First(locators ...Locator) Locator { + var f first + for _, l := range locators { + if l == nil { + continue + } + f = append(f, l) + } + return f +} + +// Locate returns the results for the first locator that returns a non-empty non-error result. +func (f first) Locate(pattern string) ([]string, error) { + var allErrors []error + for _, l := range f { + if l == nil { + continue + } + candidates, err := l.Locate(pattern) + if err != nil { + allErrors = append(allErrors, err) + continue + } + if len(candidates) > 0 { + return candidates, nil + } + } + + return nil, errors.Join(allErrors...) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/null.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/null.go new file mode 100644 index 00000000..938e481b --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/null.go @@ -0,0 +1,36 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package lookup + +import "fmt" + +// A null locator always returns an empty response. +type null struct { +} + +// Locate always returns empty for a null locator. +func (l *null) Locate(string) ([]string, error) { + return nil, nil +} + +// A notFound locator always returns an ErrNotFound error. +type notFound struct { +} + +func (l *notFound) Locate(s string) ([]string, error) { + return nil, fmt.Errorf("%s: %w", s, ErrNotFound) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/path.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/path.go new file mode 100644 index 00000000..ce692f8c --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/path.go @@ -0,0 +1,69 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package lookup + +import ( + "os" + "path" + "path/filepath" + "strings" +) + +const ( + envPath = "PATH" +) + +var ( + defaultPATH = []string{"/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin"} +) + +// GetPaths returns a list of paths for a specified root. These are constructed from the +// PATH environment variable, a default path list, and the supplied root. +func GetPaths(root string) []string { + dirs := filepath.SplitList(os.Getenv(envPath)) + + inDirs := make(map[string]bool) + for _, d := range dirs { + inDirs[d] = true + } + + // directories from the environment have higher precedence + for _, d := range defaultPATH { + if inDirs[d] { + // We don't add paths that are already included + continue + } + dirs = append(dirs, d) + } + + if root != "" && root != "/" { + rootDirs := []string{} + for _, dir := range dirs { + rootDirs = append(rootDirs, path.Join(root, dir)) + } + // directories with the root prefix have higher precedence + dirs = append(rootDirs, dirs...) + } + + return dirs +} + +// GetPath returns a colon-separated path value that can be used to set the PATH +// environment variable +func GetPath(root string) string { + return strings.Join(GetPaths(root), ":") +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root/options.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root/options.go new file mode 100644 index 00000000..273420ae --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root/options.go @@ -0,0 +1,62 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package root + +import "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + +type options struct { + logger logger.Interface + // Root represents the root from the perspective of the driver libraries and binaries. + Root string + // librarySearchPaths specifies explicit search paths for discovering libraries. + librarySearchPaths []string + // configSearchPaths specified explicit search paths for discovering driver config files. + configSearchPaths []string + versioner Versioner +} + +type Option func(*options) + +func WithLogger(logger logger.Interface) Option { + return func(o *options) { + o.logger = logger + } +} + +func WithDriverRoot(root string) Option { + return func(o *options) { + o.Root = root + } +} + +func WithLibrarySearchPaths(paths ...string) Option { + return func(o *options) { + o.librarySearchPaths = paths + } +} + +func WithConfigSearchPaths(paths ...string) Option { + return func(o *options) { + o.configSearchPaths = paths + } +} + +func WithVersioner(versioner Versioner) Option { + return func(o *options) { + o.versioner = versioner + } +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root/root.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root/root.go new file mode 100644 index 00000000..284bafd5 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root/root.go @@ -0,0 +1,243 @@ +/** +# Copyright 2023 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package root + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" +) + +// Driver represents a filesystem in which a set of drivers or devices is defined. +type Driver struct { + sync.Mutex + logger logger.Interface + // Root represents the root from the perspective of the driver libraries and binaries. + Root string + // librarySearchPaths specifies explicit search paths for discovering libraries. + librarySearchPaths []string + // configSearchPaths specified explicit search paths for discovering driver config files. + configSearchPaths []string + + // version caches the driver version. + version string + // libcudasoPath caches the path to libcuda.so.VERSION. + libcudasoPath string +} + +// New creates a new Driver root using the specified options. +func New(opts ...Option) *Driver { + o := &options{} + for _, opt := range opts { + opt(o) + } + if o.logger == nil { + o.logger = logger.New() + } + + var driverVersion string + if o.versioner != nil { + version, err := o.versioner.Version() + if err != nil { + o.logger.Warningf("Could not determine driver version: %v", err) + } + driverVersion = version + } + + d := &Driver{ + logger: o.logger, + Root: o.Root, + librarySearchPaths: o.librarySearchPaths, + configSearchPaths: o.configSearchPaths, + version: driverVersion, + libcudasoPath: "", + } + + return d +} + +// Version returns the cached driver version if possible. +// If this has not yet been initialised, the version is first updated and then returned. +func (r *Driver) Version() (string, error) { + r.Lock() + defer r.Unlock() + + if r.version == "" { + if err := r.updateInfo(); err != nil { + return "", err + } + } + + return r.version, nil +} + +// GetLibcudaParentDir returns the cached libcuda.so path if possible. +// If this has not yet been initialized, the path is first detected and then returned. +func (r *Driver) GetLibcudasoPath() (string, error) { + r.Lock() + defer r.Unlock() + + if r.libcudasoPath == "" { + if err := r.updateInfo(); err != nil { + return "", err + } + } + + return r.libcudasoPath, nil +} + +func (r *Driver) GetLibcudaParentDir() (string, error) { + libcudasoPath, err := r.GetLibcudasoPath() + if err != nil { + return "", err + } + return filepath.Dir(libcudasoPath), nil +} + +func (r *Driver) DriverLibraryLocator(additionalDirs ...string) (lookup.Locator, error) { + libcudasoParentDirPath, err := r.GetLibcudaParentDir() + if err != nil { + return nil, fmt.Errorf("failed to get libcuda.so parent directory: %w", err) + } + + searchPaths := []string{libcudasoParentDirPath} + for _, dir := range additionalDirs { + if strings.HasPrefix(dir, "/") { + searchPaths = append(searchPaths, dir) + } else { + searchPaths = append(searchPaths, filepath.Join(libcudasoParentDirPath, dir)) + } + } + + l := lookup.NewSymlinkLocator( + lookup.WithRoot(r.Root), + lookup.WithLogger(r.logger), + lookup.WithSearchPaths( + searchPaths..., + ), + lookup.WithOptional(true), + ) + return l, nil +} + +func (r *Driver) updateInfo() error { + versionSuffix := r.version + if versionSuffix == "" { + versionSuffix = "*.*" + } + + libCudaPaths, err := r.Libraries().Locate("libcuda.so." + versionSuffix) + if err != nil { + return fmt.Errorf("failed to locate libcuda.so: %w", err) + } + libcudaPath := libCudaPaths[0] + + version := strings.TrimPrefix(filepath.Base(libcudaPath), "libcuda.so.") + if version == "" { + return fmt.Errorf("failed to extract version from path %v", libcudaPath) + } + + if r.version != "" && r.version != version { + return fmt.Errorf("unexpected version detected: %v != %v", r.version, version) + } + r.version = version + r.libcudasoPath = r.RelativeToRoot(libcudaPath) + return nil +} + +// RelativeToRoot returns the specified path relative to the driver root. +func (r *Driver) RelativeToRoot(path string) string { + if r.Root == "" || r.Root == "/" { + return path + } + if !filepath.IsAbs(path) { + return path + } + + return strings.TrimPrefix(path, r.Root) +} + +// Files returns a Locator for arbitrary driver files. +func (r *Driver) Files(opts ...lookup.Option) lookup.Locator { + return lookup.NewFileLocator( + append(opts, + lookup.WithLogger(r.logger), + lookup.WithRoot(r.Root), + )..., + ) +} + +// Libraries returns a Locator for driver libraries. +func (r *Driver) Libraries() lookup.Locator { + return lookup.NewLibraryLocator( + lookup.WithLogger(r.logger), + lookup.WithRoot(r.Root), + lookup.WithSearchPaths(normalizeSearchPaths(r.librarySearchPaths...)...), + ) +} + +// Configs returns a locator for driver configs. +// If configSearchPaths is specified, these paths are used as absolute paths, +// otherwise, /etc and /usr/share are searched. +func (r *Driver) Configs() lookup.Locator { + return lookup.NewFileLocator(r.configSearchOptions()...) +} + +func (r *Driver) configSearchOptions() []lookup.Option { + if len(r.configSearchPaths) > 0 { + return []lookup.Option{ + lookup.WithLogger(r.logger), + lookup.WithRoot("/"), + lookup.WithSearchPaths(normalizeSearchPaths(r.configSearchPaths...)...), + } + } + searchPaths := []string{"/etc"} + searchPaths = append(searchPaths, xdgDataDirs()...) + return []lookup.Option{ + lookup.WithLogger(r.logger), + lookup.WithRoot(r.Root), + lookup.WithSearchPaths(searchPaths...), + } +} + +// normalizeSearchPaths takes a list of paths and normalized these. +// Each of the elements in the list is expanded if it is a path list and the +// resultant list is returned. +// This allows, for example, for the contents of `PATH` or `LD_LIBRARY_PATH` to +// be passed as a search path directly. +func normalizeSearchPaths(paths ...string) []string { + var normalized []string + for _, path := range paths { + normalized = append(normalized, filepath.SplitList(path)...) + } + return normalized +} + +// xdgDataDirs finds the paths as specified in the environment variable XDG_DATA_DIRS. +// See https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html. +func xdgDataDirs() []string { + if dirs, exists := os.LookupEnv("XDG_DATA_DIRS"); exists && dirs != "" { + return normalizeSearchPaths(dirs) + } + + return []string{"/usr/local/share", "/usr/share"} +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root/version.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root/version.go new file mode 100644 index 00000000..15f736ec --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root/version.go @@ -0,0 +1,49 @@ +/** +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package root + +import "errors" + +type Versioner interface { + Version() (string, error) +} + +func FirstOf(v ...Versioner) Versioner { + return firstVersion(v) +} + +type firstVersion []Versioner + +var _ Versioner = (firstVersion)(nil) + +func (f firstVersion) Version() (string, error) { + var errs error + for _, v := range f { + if v == nil { + continue + } + version, err := v.Version() + if err == nil { + return version, nil + } + + errs = errors.Join(errs, err) + } + + return "", errs +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks.go new file mode 100644 index 00000000..c9bab069 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks.go @@ -0,0 +1,118 @@ +/** +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package lookup + +import ( + "fmt" + "path/filepath" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks" +) + +type symlinkChain struct { + file +} + +type symlink struct { + file +} + +// NewSymlinkChainLocator creats a locator that can be used for locating files through symlinks. +func NewSymlinkChainLocator(opts ...Option) Locator { + f := newFileLocator(opts...) + l := symlinkChain{ + file: *f, + } + + return &l +} + +// NewSymlinkLocator creats a locator that can be used for locating files through symlinks. +func NewSymlinkLocator(opts ...Option) Locator { + f := newFileLocator(opts...) + l := symlink{ + file: *f, + } + + return &l +} + +// Locate finds the specified pattern at the specified root. +// If the file is a symlink, the link is followed and all candidates to the final target are returned. +func (p symlinkChain) Locate(pattern string) ([]string, error) { + candidates, err := p.file.Locate(pattern) + if err != nil { + return nil, err + } + if len(candidates) == 0 { + return candidates, nil + } + + var filenames []string + found := make(map[string]bool) + for len(candidates) > 0 { + candidate := candidates[0] + candidates = candidates[:len(candidates)-1] + if found[candidate] { + continue + } + found[candidate] = true + filenames = append(filenames, candidate) + + target, err := symlinks.Resolve(candidate) + if err != nil { + return nil, fmt.Errorf("error resolving symlink: %v", err) + } + + if !filepath.IsAbs(target) { + target, err = filepath.Abs(filepath.Join(filepath.Dir(candidate), target)) + if err != nil { + return nil, fmt.Errorf("failed to construct absolute path: %v", err) + } + } + + p.logger.Debugf("Resolved link: '%v' => '%v'", candidate, target) + if !found[target] { + candidates = append(candidates, target) + } + } + return filenames, nil +} + +// Locate finds the specified pattern at the specified root. +// If the file is a symlink, the link is resolved and the target returned. +func (p symlink) Locate(pattern string) ([]string, error) { + candidates, err := p.file.Locate(pattern) + if err != nil { + return nil, err + } + + var targets []string + seen := make(map[string]bool) + for _, candidate := range candidates { + target, err := filepath.EvalSymlinks(candidate) + if err != nil { + return nil, fmt.Errorf("failed to resolve link: %w", err) + } + if seen[target] { + continue + } + seen[target] = true + targets = append(targets, target) + } + return targets, err +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks/symlink.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks/symlink.go new file mode 100644 index 00000000..f9151a2f --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks/symlink.go @@ -0,0 +1,50 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package symlinks + +import ( + "fmt" + "os" +) + +// Resolve returns the link target of the specified filename or the filename if it is not a link. +func Resolve(filename string) (string, error) { + info, err := os.Lstat(filename) + if err != nil { + return filename, fmt.Errorf("failed to get file info: %w", err) + } + if info.Mode()&os.ModeSymlink == 0 { + return filename, nil + } + + return os.Readlink(filename) +} + +// ForceCreate creates a specified symlink. +// If a file (or empty directory) exists at the path it is removed. +func ForceCreate(target string, link string) error { + _, err := os.Lstat(link) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to get file info: %w", err) + } + if !os.IsNotExist(err) { + if err := os.Remove(link); err != nil { + return fmt.Errorf("failed to remove existing file: %w", err) + } + } + return os.Symlink(target, link) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvcaps/nvcaps.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvcaps/nvcaps.go new file mode 100644 index 00000000..48d98ccf --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvcaps/nvcaps.go @@ -0,0 +1,166 @@ +/* +# Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package nvcaps + +import ( + "bufio" + "fmt" + "io" + "log" + "os" + "path/filepath" + "strconv" + "strings" +) + +const ( + nvidiaProcDriverPath = "/proc/driver/nvidia" + nvidiaCapabilitiesPath = nvidiaProcDriverPath + "/capabilities" + + nvcapsProcDriverPath = "/proc/driver/nvidia-caps" + nvcapsMigMinorsPath = nvcapsProcDriverPath + "/mig-minors" + nvcapsDevicePath = "/dev/nvidia-caps" +) + +// MigMinor represents the minor number of a MIG device +type MigMinor int + +// MigCap represents the path to a MIG cap file +type MigCap string + +// MigCaps stores a map of MIG cap file paths to MIG minors +type MigCaps map[MigCap]MigMinor + +// NewGPUInstanceCap creates a MigCap for the specified MIG GPU instance. +// A GPU instance is uniquely defined by the GPU minor number and GI instance ID. +func NewGPUInstanceCap(gpu, gi int) MigCap { + return MigCap(fmt.Sprintf("gpu%d/gi%d/access", gpu, gi)) +} + +// NewComputeInstanceCap creates a MigCap for the specified MIG Compute instance. +// A GPU instance is uniquely defined by the GPU minor number, GI instance ID, and CI instance ID. +func NewComputeInstanceCap(gpu, gi, ci int) MigCap { + return MigCap(fmt.Sprintf("gpu%d/gi%d/ci%d/access", gpu, gi, ci)) +} + +// GetCapDevicePath returns the path to the cap device for the specified cap. +// An error is returned if the cap is invalid. +func (m MigCaps) GetCapDevicePath(cap MigCap) (string, error) { + minor, exists := m[cap] + if !exists { + return "", fmt.Errorf("invalid MIG capability path %v", cap) + } + return minor.DevicePath(), nil +} + +// NewMigCaps creates a MigCaps structure based on the contents of the MIG minors file. +func NewMigCaps() (MigCaps, error) { + // Open nvcapsMigMinorsPath for walking. + // If the nvcapsMigMinorsPath does not exist, then we are not on a MIG + // capable machine, so there is nothing to do. + // The format of this file is discussed in: + // https://docs.nvidia.com/datacenter/tesla/mig-user-guide/index.html#unique_1576522674 + minorsFile, err := os.Open(nvcapsMigMinorsPath) + if os.IsNotExist(err) { + return nil, nil + } + if err != nil { + return nil, fmt.Errorf("error opening MIG minors file: %v", err) + } + defer minorsFile.Close() + + return processMinorsFile(minorsFile), nil +} + +func processMinorsFile(minorsFile io.Reader) MigCaps { + // Walk each line of nvcapsMigMinorsPath and construct a mapping of nvidia + // capabilities path to device minor for that capability + migCaps := make(MigCaps) + scanner := bufio.NewScanner(minorsFile) + for scanner.Scan() { + cap, minor, err := processMigMinorsLine(scanner.Text()) + if err != nil { + log.Printf("Skipping line in MIG minors file: %v", err) + continue + } + migCaps[cap] = minor + } + return migCaps +} + +func processMigMinorsLine(line string) (MigCap, MigMinor, error) { + parts := strings.Split(line, " ") + if len(parts) != 2 { + return "", 0, fmt.Errorf("error processing line: %v", line) + } + + migCap := MigCap(parts[0]) + if !migCap.isValid() { + return "", 0, fmt.Errorf("invalid MIG minors line: '%v'", line) + } + + minor, err := strconv.Atoi(parts[1]) + if err != nil { + return "", 0, fmt.Errorf("error reading MIG minor from '%v': %v", line, err) + } + + return migCap, MigMinor(minor), nil +} + +func (m MigCap) isValid() bool { + cap := string(m) + switch cap { + case "config", "monitor": + return true + default: + var gpu int + var gi int + var ci int + // Look for a CI access file + n, _ := fmt.Sscanf(cap, "gpu%d/gi%d/ci%d/access", &gpu, &gi, &ci) + if n == 3 { + return true + } + // Look for a GI access file + n, _ = fmt.Sscanf(cap, "gpu%d/gi%d/access %d", &gpu, &gi) + if n == 2 { + return true + } + } + return false +} + +// ProcPath returns the proc path associated with the MIG capability +func (m MigCap) ProcPath() string { + id := string(m) + + var path string + switch id { + case "config", "monitor": + path = "mig/" + id + default: + parts := strings.SplitN(id, "/", 2) + path = strings.Join([]string{parts[0], "mig", parts[1]}, "/") + } + return filepath.Join(nvidiaCapabilitiesPath, path) +} + +// DevicePath returns the path for the nvidia-caps device with the specified +// minor number +func (m MigMinor) DevicePath() string { + return fmt.Sprintf(nvcapsDevicePath+"/nvidia-cap%d", m) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/api.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/api.go new file mode 100644 index 00000000..6275a5c2 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/api.go @@ -0,0 +1,45 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvsandboxutils + +// libraryOptions hold the parameters than can be set by a LibraryOption +type libraryOptions struct { + path string + flags int +} + +// LibraryOption represents a functional option to configure the underlying nvsandboxutils library +type LibraryOption func(*libraryOptions) + +// WithLibraryPath provides an option to set the library name to be used by the nvsandboxutils library. +func WithLibraryPath(path string) LibraryOption { + return func(o *libraryOptions) { + o.path = path + } +} + +// SetLibraryOptions applies the specified options to the nvsandboxutils library. +// If this is called when a library is already loaded, an error is raised. +func SetLibraryOptions(opts ...LibraryOption) error { + libnvsandboxutils.Lock() + defer libnvsandboxutils.Unlock() + if libnvsandboxutils.refcount != 0 { + return errLibraryAlreadyLoaded + } + libnvsandboxutils.init(opts...) + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/cgo_helpers.h b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/cgo_helpers.h new file mode 100644 index 00000000..23b3c256 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/cgo_helpers.h @@ -0,0 +1,25 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +// WARNING: THIS FILE WAS AUTOMATICALLY GENERATED. +// Code generated by https://git.io/c-for-go. DO NOT EDIT. + +#include "nvsandboxutils.h" +#include +#pragma once + +#define __CGOGEN 1 + diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/cgo_helpers_static.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/cgo_helpers_static.go new file mode 100644 index 00000000..5924d622 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/cgo_helpers_static.go @@ -0,0 +1,38 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvsandboxutils + +var cgoAllocsUnknown = new(struct{}) + +func clen(n []byte) int { + for i := 0; i < len(n); i++ { + if n[i] == 0 { + return i + } + } + return len(n) +} + +// Creates an int8 array of fixed input length to store the Go string. +// TODO: Add error check if input string has a length greater than INPUT_LENGTH +func convertStringToFixedArray(str string) [INPUT_LENGTH]int8 { + var output [INPUT_LENGTH]int8 + for i, s := range str { + output[i] = int8(s) + } + return output +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/const.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/const.go new file mode 100644 index 00000000..9e8cdf3f --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/const.go @@ -0,0 +1,156 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +// WARNING: THIS FILE WAS AUTOMATICALLY GENERATED. +// Code generated by https://git.io/c-for-go. DO NOT EDIT. + +package nvsandboxutils + +/* +#cgo linux LDFLAGS: -Wl,--export-dynamic -Wl,--unresolved-symbols=ignore-in-object-files +#cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup +#include "nvsandboxutils.h" +#include +#include "cgo_helpers.h" +*/ +import "C" + +const ( + // INPUT_LENGTH as defined in nvsandboxutils/nvsandboxutils.h + INPUT_LENGTH = 256 + // MAX_FILE_PATH as defined in nvsandboxutils/nvsandboxutils.h + MAX_FILE_PATH = 256 + // MAX_NAME_LENGTH as defined in nvsandboxutils/nvsandboxutils.h + MAX_NAME_LENGTH = 256 +) + +// Ret as declared in nvsandboxutils/nvsandboxutils.h +type Ret int32 + +// Ret enumeration from nvsandboxutils/nvsandboxutils.h +const ( + SUCCESS Ret = iota + ERROR_UNINITIALIZED Ret = 1 + ERROR_NOT_SUPPORTED Ret = 2 + ERROR_INVALID_ARG Ret = 3 + ERROR_INSUFFICIENT_SIZE Ret = 4 + ERROR_VERSION_NOT_SUPPORTED Ret = 5 + ERROR_LIBRARY_LOAD Ret = 6 + ERROR_FUNCTION_NOT_FOUND Ret = 7 + ERROR_DEVICE_NOT_FOUND Ret = 8 + ERROR_NVML_LIB_CALL Ret = 9 + ERROR_OUT_OF_MEMORY Ret = 10 + ERROR_FILEPATH_NOT_FOUND Ret = 11 + ERROR_UNKNOWN Ret = 65535 +) + +// LogLevel as declared in nvsandboxutils/nvsandboxutils.h +type LogLevel int32 + +// LogLevel enumeration from nvsandboxutils/nvsandboxutils.h +const ( + LOG_LEVEL_FATAL LogLevel = iota + LOG_LEVEL_ERROR LogLevel = 1 + LOG_LEVEL_WARN LogLevel = 2 + LOG_LEVEL_DEBUG LogLevel = 3 + LOG_LEVEL_INFO LogLevel = 4 + LOG_LEVEL_NONE LogLevel = 65535 +) + +// RootfsInputType as declared in nvsandboxutils/nvsandboxutils.h +type RootfsInputType int32 + +// RootfsInputType enumeration from nvsandboxutils/nvsandboxutils.h +const ( + NV_ROOTFS_DEFAULT RootfsInputType = iota + NV_ROOTFS_PATH RootfsInputType = 1 + NV_ROOTFS_PID RootfsInputType = 2 +) + +// FileType as declared in nvsandboxutils/nvsandboxutils.h +type FileType int32 + +// FileType enumeration from nvsandboxutils/nvsandboxutils.h +const ( + NV_DEV FileType = iota + NV_PROC FileType = 1 + NV_SYS FileType = 2 +) + +// FileSystemSubType as declared in nvsandboxutils/nvsandboxutils.h +type FileSystemSubType int32 + +// FileSystemSubType enumeration from nvsandboxutils/nvsandboxutils.h +const ( + NV_DEV_NVIDIA FileSystemSubType = iota + NV_DEV_DRI_CARD FileSystemSubType = 1 + NV_DEV_DRI_RENDERD FileSystemSubType = 2 + NV_DEV_DRI_CARD_SYMLINK FileSystemSubType = 3 + NV_DEV_DRI_RENDERD_SYMLINK FileSystemSubType = 4 + NV_DEV_NVIDIA_UVM FileSystemSubType = 5 + NV_DEV_NVIDIA_UVM_TOOLS FileSystemSubType = 6 + NV_DEV_NVIDIA_MODESET FileSystemSubType = 7 + NV_DEV_NVIDIA_CTL FileSystemSubType = 8 + NV_DEV_GDRDRV FileSystemSubType = 9 + NV_DEV_NVIDIA_CAPS_NVIDIA_CAP FileSystemSubType = 10 + NV_PROC_DRIVER_NVIDIA_GPUS_PCIBUSID FileSystemSubType = 11 + NV_PROC_DRIVER_NVIDIA_GPUS FileSystemSubType = 12 + NV_PROC_NVIDIA_PARAMS FileSystemSubType = 13 + NV_PROC_NVIDIA_CAPS_MIG_MINORS FileSystemSubType = 14 + NV_PROC_DRIVER_NVIDIA_CAPABILITIES_GPU FileSystemSubType = 15 + NV_PROC_DRIVER_NVIDIA_CAPABILITIES FileSystemSubType = 16 + NV_PROC_DRIVER_NVIDIA_CAPABILITIIES_GPU_MIG_CI_ACCESS FileSystemSubType = 17 + NV_SYS_MODULE_NVIDIA_DRIVER_PCIBUSID FileSystemSubType = 18 + NV_SYS_MODULE_NVIDIA_DRIVER FileSystemSubType = 19 + NV_NUM_SUBTYPE FileSystemSubType = 20 +) + +// FileModule as declared in nvsandboxutils/nvsandboxutils.h +type FileModule int32 + +// FileModule enumeration from nvsandboxutils/nvsandboxutils.h +const ( + NV_GPU FileModule = iota + NV_MIG FileModule = 1 + NV_DRIVER_NVIDIA FileModule = 2 + NV_DRIVER_NVIDIA_UVM FileModule = 3 + NV_DRIVER_NVIDIA_MODESET FileModule = 4 + NV_DRIVER_GDRDRV FileModule = 5 + NV_SYSTEM FileModule = 6 +) + +// FileFlag as declared in nvsandboxutils/nvsandboxutils.h +type FileFlag int32 + +// FileFlag enumeration from nvsandboxutils/nvsandboxutils.h +const ( + NV_FILE_FLAG_HINT FileFlag = 1 + NV_FILE_FLAG_MASKOUT FileFlag = 2 + NV_FILE_FLAG_CONTENT FileFlag = 4 + NV_FILE_FLAG_DEPRECTATED FileFlag = 8 + NV_FILE_FLAG_CANDIDATES FileFlag = 16 +) + +// GpuInputType as declared in nvsandboxutils/nvsandboxutils.h +type GpuInputType int32 + +// GpuInputType enumeration from nvsandboxutils/nvsandboxutils.h +const ( + NV_GPU_INPUT_GPU_UUID GpuInputType = iota + NV_GPU_INPUT_MIG_UUID GpuInputType = 1 + NV_GPU_INPUT_PCI_ID GpuInputType = 2 + NV_GPU_INPUT_PCI_INDEX GpuInputType = 3 +) diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/doc.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/doc.go new file mode 100644 index 00000000..231c68c2 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/doc.go @@ -0,0 +1,23 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +// WARNING: THIS FILE WAS AUTOMATICALLY GENERATED. +// Code generated by https://git.io/c-for-go. DO NOT EDIT. + +/* +Package NVSANDBOXUTILS bindings +*/ +package nvsandboxutils diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/dynamicLibrary_mock.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/dynamicLibrary_mock.go new file mode 100644 index 00000000..a22e5669 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/dynamicLibrary_mock.go @@ -0,0 +1,157 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package nvsandboxutils + +import ( + "sync" +) + +// Ensure, that dynamicLibraryMock does implement dynamicLibrary. +// If this is not the case, regenerate this file with moq. +var _ dynamicLibrary = &dynamicLibraryMock{} + +// dynamicLibraryMock is a mock implementation of dynamicLibrary. +// +// func TestSomethingThatUsesdynamicLibrary(t *testing.T) { +// +// // make and configure a mocked dynamicLibrary +// mockeddynamicLibrary := &dynamicLibraryMock{ +// CloseFunc: func() error { +// panic("mock out the Close method") +// }, +// LookupFunc: func(s string) error { +// panic("mock out the Lookup method") +// }, +// OpenFunc: func() error { +// panic("mock out the Open method") +// }, +// } +// +// // use mockeddynamicLibrary in code that requires dynamicLibrary +// // and then make assertions. +// +// } +type dynamicLibraryMock struct { + // CloseFunc mocks the Close method. + CloseFunc func() error + + // LookupFunc mocks the Lookup method. + LookupFunc func(s string) error + + // OpenFunc mocks the Open method. + OpenFunc func() error + + // calls tracks calls to the methods. + calls struct { + // Close holds details about calls to the Close method. + Close []struct { + } + // Lookup holds details about calls to the Lookup method. + Lookup []struct { + // S is the s argument value. + S string + } + // Open holds details about calls to the Open method. + Open []struct { + } + } + lockClose sync.RWMutex + lockLookup sync.RWMutex + lockOpen sync.RWMutex +} + +// Close calls CloseFunc. +func (mock *dynamicLibraryMock) Close() error { + callInfo := struct { + }{} + mock.lockClose.Lock() + mock.calls.Close = append(mock.calls.Close, callInfo) + mock.lockClose.Unlock() + if mock.CloseFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.CloseFunc() +} + +// CloseCalls gets all the calls that were made to Close. +// Check the length with: +// +// len(mockeddynamicLibrary.CloseCalls()) +func (mock *dynamicLibraryMock) CloseCalls() []struct { +} { + var calls []struct { + } + mock.lockClose.RLock() + calls = mock.calls.Close + mock.lockClose.RUnlock() + return calls +} + +// Lookup calls LookupFunc. +func (mock *dynamicLibraryMock) Lookup(s string) error { + callInfo := struct { + S string + }{ + S: s, + } + mock.lockLookup.Lock() + mock.calls.Lookup = append(mock.calls.Lookup, callInfo) + mock.lockLookup.Unlock() + if mock.LookupFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.LookupFunc(s) +} + +// LookupCalls gets all the calls that were made to Lookup. +// Check the length with: +// +// len(mockeddynamicLibrary.LookupCalls()) +func (mock *dynamicLibraryMock) LookupCalls() []struct { + S string +} { + var calls []struct { + S string + } + mock.lockLookup.RLock() + calls = mock.calls.Lookup + mock.lockLookup.RUnlock() + return calls +} + +// Open calls OpenFunc. +func (mock *dynamicLibraryMock) Open() error { + callInfo := struct { + }{} + mock.lockOpen.Lock() + mock.calls.Open = append(mock.calls.Open, callInfo) + mock.lockOpen.Unlock() + if mock.OpenFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.OpenFunc() +} + +// OpenCalls gets all the calls that were made to Open. +// Check the length with: +// +// len(mockeddynamicLibrary.OpenCalls()) +func (mock *dynamicLibraryMock) OpenCalls() []struct { +} { + var calls []struct { + } + mock.lockOpen.RLock() + calls = mock.calls.Open + mock.lockOpen.RUnlock() + return calls +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/gpu-resources.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/gpu-resources.go new file mode 100644 index 00000000..19dec07e --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/gpu-resources.go @@ -0,0 +1,67 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvsandboxutils + +import ( + "strings" + "unsafe" +) + +import "C" + +type GpuResource struct { + Version uint32 +} + +type GpuFileInfo struct { + Path string + Type FileType + SubType FileSystemSubType + Module FileModule + Flags FileFlag +} + +func (l *library) GetGpuResource(uuid string) ([]GpuFileInfo, Ret) { + deviceType := NV_GPU_INPUT_GPU_UUID + if strings.HasPrefix(uuid, "MIG-") { + deviceType = NV_GPU_INPUT_MIG_UUID + } + + request := GpuRes{ + Version: 1, + InputType: uint32(deviceType), + Input: convertStringToFixedArray(uuid), + } + + ret := nvSandboxUtilsGetGpuResource(&request) + if ret != SUCCESS { + return nil, ret + } + + var fileInfos []GpuFileInfo + for fileInfo := request.Files; fileInfo != nil; fileInfo = fileInfo.Next { + fi := GpuFileInfo{ + Path: C.GoString((*C.char)(unsafe.Pointer(fileInfo.FilePath))), + Type: FileType(fileInfo.FileType), + SubType: FileSystemSubType(fileInfo.FileSubType), + Module: FileModule(fileInfo.Module), + Flags: FileFlag(fileInfo.Flags), + } + fileInfos = append(fileInfos, fi) + } + return fileInfos, SUCCESS +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/impl.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/impl.go new file mode 100644 index 00000000..0f6948a2 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/impl.go @@ -0,0 +1,64 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvsandboxutils + +import "C" + +func (l *library) Init(path string) Ret { + if err := l.load(); err != nil { + return ERROR_LIBRARY_LOAD + } + + input := InitInput{ + Version: 1, + Type: uint32(NV_ROOTFS_PATH), + Value: convertStringToFixedArray(path), + } + + return nvSandboxUtilsInit(&input) +} + +func (l *library) Shutdown() Ret { + ret := nvSandboxUtilsShutdown() + if ret != SUCCESS { + return ret + } + + err := l.close() + if err != nil { + return ERROR_UNKNOWN + } + + return ret +} + +// TODO: Is this length specified in the header file? +const VERSION_LENGTH = 100 + +func (l *library) GetDriverVersion() (string, Ret) { + Version := make([]byte, VERSION_LENGTH) + ret := nvSandboxUtilsGetDriverVersion(&Version[0], VERSION_LENGTH) + return string(Version[:clen(Version)]), ret +} + +func (l *library) GetFileContent(path string) (string, Ret) { + Content := make([]byte, MAX_FILE_PATH) + FilePath := []byte(path + string(byte(0))) + Size := uint32(MAX_FILE_PATH) + ret := nvSandboxUtilsGetFileContent(&FilePath[0], &Content[0], &Size) + return string(Content[:clen(Content)]), ret +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/lib.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/lib.go new file mode 100644 index 00000000..2872e107 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/lib.go @@ -0,0 +1,156 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvsandboxutils + +import ( + "errors" + "fmt" + "sync" + + "github.com/NVIDIA/go-nvml/pkg/dl" +) + +const ( + defaultNvSandboxUtilsLibraryName = "libnvidia-sandboxutils.so.1" + defaultNvSandboxUtilsLibraryLoadFlags = dl.RTLD_LAZY | dl.RTLD_GLOBAL +) + +var errLibraryNotLoaded = errors.New("library not loaded") +var errLibraryAlreadyLoaded = errors.New("library already loaded") + +// dynamicLibrary is an interface for abstacting the underlying library. +// This also allows for mocking and testing. + +//go:generate moq -rm -fmt=goimports -stub -out dynamicLibrary_mock.go . dynamicLibrary +type dynamicLibrary interface { + Lookup(string) error + Open() error + Close() error +} + +// library represents an nvsandboxutils library. +// This includes a reference to the underlying DynamicLibrary +type library struct { + sync.Mutex + path string + refcount refcount + dl dynamicLibrary +} + +// libnvsandboxutils is a global instance of the nvsandboxutils library. +var libnvsandboxutils = newLibrary() + +func New(opts ...LibraryOption) Interface { + return newLibrary(opts...) +} + +func newLibrary(opts ...LibraryOption) *library { + l := &library{} + l.init(opts...) + return l +} + +func (l *library) init(opts ...LibraryOption) { + o := libraryOptions{} + for _, opt := range opts { + opt(&o) + } + + if o.path == "" { + o.path = defaultNvSandboxUtilsLibraryName + } + if o.flags == 0 { + o.flags = defaultNvSandboxUtilsLibraryLoadFlags + } + + l.path = o.path + l.dl = dl.New(o.path, o.flags) +} + +// LookupSymbol checks whether the specified library symbol exists in the library. +// Note that this requires that the library be loaded. +func (l *library) LookupSymbol(name string) error { + if l == nil || l.refcount == 0 { + return fmt.Errorf("error looking up %s: %w", name, errLibraryNotLoaded) + } + return l.dl.Lookup(name) +} + +// load initializes the library and updates the versioned symbols. +// Multiple calls to an already loaded library will return without error. +func (l *library) load() (rerr error) { + l.Lock() + defer l.Unlock() + + defer func() { l.refcount.IncOnNoError(rerr) }() + if l.refcount > 0 { + return nil + } + + if err := l.dl.Open(); err != nil { + return fmt.Errorf("error opening %s: %w", l.path, err) + } + + // Update the errorStringFunc to point to nvsandboxutils.ErrorString + errorStringFunc = nvsanboxutilsErrorString + + // Update all versioned symbols + l.updateVersionedSymbols() + + return nil +} + +// close the underlying library and ensure that the global pointer to the +// library is set to nil to ensure that subsequent calls to open will reinitialize it. +// Multiple calls to an already closed nvsandboxutils library will return without error. +func (l *library) close() (rerr error) { + l.Lock() + defer l.Unlock() + + defer func() { l.refcount.DecOnNoError(rerr) }() + if l.refcount != 1 { + return nil + } + + if err := l.dl.Close(); err != nil { + return fmt.Errorf("error closing %s: %w", l.path, err) + } + + // Update the errorStringFunc to point to defaultErrorStringFunc + errorStringFunc = defaultErrorStringFunc + + return nil +} + +// Default all versioned APIs to v1 (to infer the types) +var ( +// Insert default versions for APIs here. +// Example: +// nvsandboxUtilsFunction = nvsandboxUtilsFunction_v1 +) + +// updateVersionedSymbols checks for versioned symbols in the loaded dynamic library. +// If newer versioned symbols exist, these replace the default `v1` symbols initialized above. +// When new versioned symbols are added, these would have to be initialized above and have +// corresponding checks and subsequent assignments added below. +func (l *library) updateVersionedSymbols() { + // Example: + // err := l.dl.Lookup("nvsandboxUtilsFunction_v2") + // if err == nil { + // nvsandboxUtilsFunction = nvsandboxUtilsFunction_v2 + // } +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/nvsandboxutils.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/nvsandboxutils.go new file mode 100644 index 00000000..29544bc9 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/nvsandboxutils.go @@ -0,0 +1,72 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +// WARNING: THIS FILE WAS AUTOMATICALLY GENERATED. +// Code generated by https://git.io/c-for-go. DO NOT EDIT. + +package nvsandboxutils + +/* +#cgo linux LDFLAGS: -Wl,--export-dynamic -Wl,--unresolved-symbols=ignore-in-object-files +#cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup +#include "nvsandboxutils.h" +#include +#include "cgo_helpers.h" +*/ +import "C" +import "unsafe" + +// nvSandboxUtilsInit function as declared in nvsandboxutils/nvsandboxutils.h +func nvSandboxUtilsInit(Input *InitInput) Ret { + cInput, _ := (*C.nvSandboxUtilsInitInput_t)(unsafe.Pointer(Input)), cgoAllocsUnknown + __ret := C.nvSandboxUtilsInit(cInput) + __v := (Ret)(__ret) + return __v +} + +// nvSandboxUtilsShutdown function as declared in nvsandboxutils/nvsandboxutils.h +func nvSandboxUtilsShutdown() Ret { + __ret := C.nvSandboxUtilsShutdown() + __v := (Ret)(__ret) + return __v +} + +// nvSandboxUtilsGetDriverVersion function as declared in nvsandboxutils/nvsandboxutils.h +func nvSandboxUtilsGetDriverVersion(Version *byte, Length uint32) Ret { + cVersion, _ := (*C.char)(unsafe.Pointer(Version)), cgoAllocsUnknown + cLength, _ := (C.uint)(Length), cgoAllocsUnknown + __ret := C.nvSandboxUtilsGetDriverVersion(cVersion, cLength) + __v := (Ret)(__ret) + return __v +} + +// nvSandboxUtilsGetGpuResource function as declared in nvsandboxutils/nvsandboxutils.h +func nvSandboxUtilsGetGpuResource(Request *GpuRes) Ret { + cRequest, _ := (*C.nvSandboxUtilsGpuRes_t)(unsafe.Pointer(Request)), cgoAllocsUnknown + __ret := C.nvSandboxUtilsGetGpuResource(cRequest) + __v := (Ret)(__ret) + return __v +} + +// nvSandboxUtilsGetFileContent function as declared in nvsandboxutils/nvsandboxutils.h +func nvSandboxUtilsGetFileContent(FilePath *byte, Content *byte, ContentSize *uint32) Ret { + cFilePath, _ := (*C.char)(unsafe.Pointer(FilePath)), cgoAllocsUnknown + cContent, _ := (*C.char)(unsafe.Pointer(Content)), cgoAllocsUnknown + cContentSize, _ := (*C.uint)(unsafe.Pointer(ContentSize)), cgoAllocsUnknown + __ret := C.nvSandboxUtilsGetFileContent(cFilePath, cContent, cContentSize) + __v := (Ret)(__ret) + return __v +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/nvsandboxutils.h b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/nvsandboxutils.h new file mode 100644 index 00000000..3c66e159 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/nvsandboxutils.h @@ -0,0 +1,298 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NVSANDBOXUTILS_H__ +#define __NVSANDBOXUTILS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define INPUT_LENGTH 256 +#define MAX_FILE_PATH 256 +#define MAX_NAME_LENGTH 256 + +/***************************************************************************************************/ +/** @defgroup enums Enumerations + * @{ + */ +/***************************************************************************************************/ + +/** + * Return types + */ +typedef enum +{ + NVSANDBOXUTILS_SUCCESS = 0, //!< The operation was successful + NVSANDBOXUTILS_ERROR_UNINITIALIZED = 1, //!< The library wasn't successfully initialized + NVSANDBOXUTILS_ERROR_NOT_SUPPORTED = 2, //!< The requested operation is not supported on target device + NVSANDBOXUTILS_ERROR_INVALID_ARG = 3, //!< A supplied argument is invalid + NVSANDBOXUTILS_ERROR_INSUFFICIENT_SIZE = 4, //!< A supplied argument is not large enough + NVSANDBOXUTILS_ERROR_VERSION_NOT_SUPPORTED = 5, //!< Requested library version is not supported + NVSANDBOXUTILS_ERROR_LIBRARY_LOAD = 6, //!< The library load failed + NVSANDBOXUTILS_ERROR_FUNCTION_NOT_FOUND = 7, //!< Called function was not found + NVSANDBOXUTILS_ERROR_DEVICE_NOT_FOUND = 8, //!< Target device was not found + NVSANDBOXUTILS_ERROR_NVML_LIB_CALL = 9, //!< NVML library call failed + NVSANDBOXUTILS_ERROR_OUT_OF_MEMORY = 10, //!< There is insufficient memory + NVSANDBOXUTILS_ERROR_FILEPATH_NOT_FOUND = 11, //!< A supplied file path was not found + NVSANDBOXUTILS_ERROR_UNKNOWN = 0xFFFF, //!< Unknown error occurred +} nvSandboxUtilsRet_t; + +/** + * Return if there is an error + */ +#define RETURN_ON_SANDBOX_ERROR(result) \ + if ((result) != NVSANDBOXUTILS_SUCCESS) { \ + NVSANDBOXUTILS_ERROR_MSG("%s %d result=%d", __func__, __LINE__, result); \ + return result; \ + } + +/** + * Log levels + */ +typedef enum +{ + NVSANDBOXUTILS_LOG_LEVEL_FATAL = 0, //!< Log fatal errors + NVSANDBOXUTILS_LOG_LEVEL_ERROR = 1, //!< Log all errors + NVSANDBOXUTILS_LOG_LEVEL_WARN = 2, //!< Log all warnings + NVSANDBOXUTILS_LOG_LEVEL_DEBUG = 3, //!< Log all debug messages + NVSANDBOXUTILS_LOG_LEVEL_INFO = 4, //!< Log all info messages + NVSANDBOXUTILS_LOG_LEVEL_NONE = 0xFFFF, //!< Log none +} nvSandboxUtilsLogLevel_t; + +/** + * Input rootfs to help access files inside the driver container + */ +typedef enum +{ + NV_ROOTFS_DEFAULT, //!< Default no rootfs + NV_ROOTFS_PATH, //!< /run/nvidia/driver + NV_ROOTFS_PID, //!< /proc/PID/mountinfo +} nvSandboxUtilsRootfsInputType_t; + +/** + * File type + */ +typedef enum +{ + NV_DEV, //!< /dev file system + NV_PROC, //!< /proc file system + NV_SYS, //!< /sys file system +} nvSandboxUtilsFileType_t; + +/** + * File subtype + */ +typedef enum +{ + NV_DEV_NVIDIA, //!< /dev/nvidia0 + NV_DEV_DRI_CARD, //!< /dev/dri/card1 + NV_DEV_DRI_RENDERD, //!< /dev/dri/renderD128 + NV_DEV_DRI_CARD_SYMLINK, //!< /dev/dri/by-path/pci-0000:41:00.0-card + NV_DEV_DRI_RENDERD_SYMLINK, //!< /dev/dri/by-path/pci-0000:41:00.0-render + NV_DEV_NVIDIA_UVM, //!< /dev/nvidia-uvm + NV_DEV_NVIDIA_UVM_TOOLS, //!< /dev/nvidia-uvm-tools + NV_DEV_NVIDIA_MODESET, //!< /dev/nvidia-uvm-modeset + NV_DEV_NVIDIA_CTL, //!< /dev/nvidiactl + NV_DEV_GDRDRV, //!< /dev/gdrdrv + NV_DEV_NVIDIA_CAPS_NVIDIA_CAP, //!< /dev/nvidia-caps/nvidia-cap22 + NV_PROC_DRIVER_NVIDIA_GPUS_PCIBUSID, //!< /proc/driver/nvidia/gpus/0000:2d:00.0 + NV_PROC_DRIVER_NVIDIA_GPUS, //!< /proc/driver/nvidia/gpus (for mask out) + NV_PROC_NVIDIA_PARAMS, //!< /proc/driver/nvidia/params + NV_PROC_NVIDIA_CAPS_MIG_MINORS, //!< /proc/driver/nvidia-caps/mig-minors + NV_PROC_DRIVER_NVIDIA_CAPABILITIES_GPU, //!< /proc/driver/nvidia/capabilities/gpu0 + NV_PROC_DRIVER_NVIDIA_CAPABILITIES, //!< /proc/driver/nvidia/capabilities (for mask out) + NV_PROC_DRIVER_NVIDIA_CAPABILITIIES_GPU_MIG_CI_ACCESS, //!< proc/driver/nvidia/capabilities/gpu0/mig/gi2/ci0/access + NV_SYS_MODULE_NVIDIA_DRIVER_PCIBUSID, //!< /sys/module/nvidia/drivers/pci:nvidia/0000:2d:00.0 + NV_SYS_MODULE_NVIDIA_DRIVER, //!< /sys/module/nvidia/drivers/pci:nvidia (for mask out) + NV_NUM_SUBTYPE, // always at the end. +} nvSandboxUtilsFileSystemSubType_t; + +/** + * File module + */ +typedef enum +{ + NV_GPU, //!< Target device + NV_MIG, //!< Target device- MIG + NV_DRIVER_NVIDIA, //!< NVIDIA kernel driver + NV_DRIVER_NVIDIA_UVM, //!< NVIDIA kernel driver-UVM + NV_DRIVER_NVIDIA_MODESET, //!< NVIDIA kernel driver-modeset + NV_DRIVER_GDRDRV, //!< GDRDRV driver + NV_SYSTEM, //!< System module +} nvSandboxUtilsFileModule_t; + +/** + * Flag to provide additional details about the file + */ +typedef enum +{ + NV_FILE_FLAG_HINT = (1 << 0), //!< Default no hint + NV_FILE_FLAG_MASKOUT = (1 << 1), //!< For /proc/driver/nvidia/gpus + NV_FILE_FLAG_CONTENT = (1 << 2), //!< For /proc/driver/nvidia/params + //!< For SYMLINK + //!< Use \p nvSandboxUtilsGetFileContent to get name of the linked file + NV_FILE_FLAG_DEPRECTATED = (1 << 3), //!< For all the FIRMWARE GSP file + NV_FILE_FLAG_CANDIDATES = (1 << 4), //!< For libcuda.so +} nvSandboxUtilsFileFlag_t; + +/** + * Input type of the target device + */ +typedef enum +{ + NV_GPU_INPUT_GPU_UUID, //!< GPU UUID + NV_GPU_INPUT_MIG_UUID, //!< MIG UUID + NV_GPU_INPUT_PCI_ID, //!< PCIe DBDF ID + NV_GPU_INPUT_PCI_INDEX, //!< PCIe bus order (0 points to the GPU that has lowest PCIe BDF) +} nvSandboxUtilsGpuInputType_t; + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup dataTypes Structures and Unions + * @{ + */ +/***************************************************************************************************/ + +/** + * Initalization input v1 + */ +typedef struct +{ + unsigned int version; //!< Version for the structure + nvSandboxUtilsRootfsInputType_t type; //!< One of \p nvSandboxUtilsRootfsInputType_t + char value[INPUT_LENGTH]; //!< String representation of input +} nvSandboxUtilsInitInput_v1_t; + +typedef nvSandboxUtilsInitInput_v1_t nvSandboxUtilsInitInput_t; + +/** + * File system information + */ +typedef struct nvSandboxUtilsGpuFileInfo_v1_t +{ + struct nvSandboxUtilsGpuFileInfo_v1_t *next; //!< Pointer to the next node in the linked list + nvSandboxUtilsFileType_t fileType; //!< One of \p nvSandboxUtilsFileType_t + nvSandboxUtilsFileSystemSubType_t fileSubType; //!< One of \p nvSandboxUtilsFileSystemSubType_t + nvSandboxUtilsFileModule_t module; //!< One of \p nvSandboxUtilsFileModule_t + nvSandboxUtilsFileFlag_t flags; //!< One of \p nvSandboxUtilsFileFlag_t + char *filePath; //!< Relative file path to rootfs +}nvSandboxUtilsGpuFileInfo_v1_t; + +/** + * GPU resource request v1 + */ +typedef struct +{ + unsigned int version; //!< Version for the structure + nvSandboxUtilsGpuInputType_t inputType; //!< One of \p nvSandboxUtilsGpuInputType_t + char input[INPUT_LENGTH]; //!< String representation of input + nvSandboxUtilsGpuFileInfo_v1_t *files; //!< Linked list of \ref nvSandboxUtilsGpuFileInfo_v1_t +} nvSandboxUtilsGpuRes_v1_t; + +typedef nvSandboxUtilsGpuRes_v1_t nvSandboxUtilsGpuRes_t; + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup funcs Functions + * @{ + */ +/***************************************************************************************************/ + +/* ************************************************* + * Initialize library + * ************************************************* + */ +/** + * Prepare library resources before library API can be used. + * This initialization will not fail if one of the initialization prerequisites fails. + * @param input Reference to the called-supplied input struct that has initialization fields + * + * @returns @ref NVSANDBOXUTILS_SUCCESS on success + * @returns @ref NVSANDBOXUTILS_ERROR_INVALID_ARG if \p input->value isn't a valid rootfs path + * @returns @ref NVSANDBOXUTILS_ERROR_VERSION_NOT_SUPPORTED if \p input->version isn't supported by the library + * @returns @ref NVSANDBOXUTILS_ERROR_FILEPATH_NOT_FOUND if any of the required file paths are not found during initialization + * @returns @ref NVSANDBOXUTILS_ERROR_OUT_OF_MEMORY if there is insufficient system memory during initialization + * @returns @ref NVSANDBOXUTILS_ERROR_LIBRARY_LOAD on any error during loading the library + */ +nvSandboxUtilsRet_t nvSandboxUtilsInit(nvSandboxUtilsInitInput_t *input); + +/* ************************************************* + * Shutdown library + * ************************************************* + */ +/** + * Clean up library resources created by init call + * + * @returns @ref NVSANDBOXUTILS_SUCCESS on success + */ +nvSandboxUtilsRet_t nvSandboxUtilsShutdown(void); + +/* ************************************************* + * Get NVIDIA RM driver version + * ************************************************* + */ +/** + * Get NVIDIA RM driver version + * @param version Reference to caller-supplied buffer to return driver version string + * @param length The maximum allowed length of the string returned in \p version + * + * @returns @ref NVSANDBOXUTILS_SUCCESS on success + * @returns @ref NVSANDBOXUTILS_ERROR_INVALID_ARG if \p version is NULL + * @returns @ref NVSANDBOXUTILS_ERROR_NVML_LIB_CALL on any error during driver version query from NVML + */ +nvSandboxUtilsRet_t nvSandboxUtilsGetDriverVersion(char *version, unsigned int length); + +/* ************************************************* + * Get /dev, /proc, /sys file system information + * ************************************************* + */ +/** + * Get /dev, /proc, /sys file system information + * @param request Reference to caller-supplied request struct to return the file system information + * + * @returns @ref NVSANDBOXUTILS_SUCCESS on success + * @returns @ref NVSANDBOXUTILS_ERROR_INVALID_ARG if \p request->input doesn't match any device + * @returns @ref NVSANDBOXUTILS_ERROR_VERSION_NOT_SUPPORTED if \p request->version isn't supported by the library + */ +nvSandboxUtilsRet_t nvSandboxUtilsGetGpuResource(nvSandboxUtilsGpuRes_t *request); + +/* ************************************************* + * Get content of given file path + * ************************************************* + */ +/** + * Get file content of input file path + * @param filePath Reference to the file path + * @param content Reference to the caller-supplied buffer to return the file content + * @param contentSize Reference to the maximum allowed size of content. It is updated to the actual size of the content on return + * + * @returns @ref NVSANDBOXUTILS_SUCCESS on success + * @returns @ref NVSANDBOXUTILS_ERROR_INVALID_ARG if \p filePath or \p content is NULL + * @returns @ref NVSANDBOXUTILS_ERROR_INSUFFICIENT_SIZE if \p contentSize is too small + * @returns @ref NVSANDBOXUTILS_ERROR_FILEPATH_NOT_FOUND on an error while obtaining the content for the file path + */ +nvSandboxUtilsRet_t nvSandboxUtilsGetFileContent(char *filePath, char *content, unsigned int *contentSize); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // __NVSANDBOXUTILS_H__ diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/refcount.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/refcount.go new file mode 100644 index 00000000..f93107b0 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/refcount.go @@ -0,0 +1,31 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvsandboxutils + +type refcount int + +func (r *refcount) IncOnNoError(err error) { + if err == nil { + (*r)++ + } +} + +func (r *refcount) DecOnNoError(err error) { + if err == nil && (*r) > 0 { + (*r)-- + } +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/return.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/return.go new file mode 100644 index 00000000..90d4ed84 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/return.go @@ -0,0 +1,74 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvsandboxutils + +import ( + "fmt" +) + +// nvsandboxutils.ErrorString() +func (l *library) ErrorString(r Ret) string { + return r.Error() +} + +// String returns the string representation of a Ret. +func (r Ret) String() string { + return r.Error() +} + +// Error returns the string representation of a Ret. +func (r Ret) Error() string { + return errorStringFunc(r) +} + +// Assigned to nvsandboxutils.ErrorString if the system nvsandboxutils library is in use. +var errorStringFunc = defaultErrorStringFunc + +// nvsanboxutilsErrorString is an alias for the default error string function. +var nvsanboxutilsErrorString = defaultErrorStringFunc + +// defaultErrorStringFunc provides a basic nvsandboxutils.ErrorString implementation. +// This allows the nvsandboxutils.ErrorString function to be used even if the nvsandboxutils library +// is not loaded. +var defaultErrorStringFunc = func(r Ret) string { + switch r { + case SUCCESS: + return "SUCCESS" + case ERROR_UNINITIALIZED: + return "ERROR_UNINITIALIZED" + case ERROR_NOT_SUPPORTED: + return "ERROR_NOT_SUPPORTED" + case ERROR_INVALID_ARG: + return "ERROR_INVALID_ARG" + case ERROR_INSUFFICIENT_SIZE: + return "ERROR_INSUFFICIENT_SIZE" + case ERROR_VERSION_NOT_SUPPORTED: + return "ERROR_VERSION_NOT_SUPPORTED" + case ERROR_LIBRARY_LOAD: + return "ERROR_LIBRARY_LOAD" + case ERROR_FUNCTION_NOT_FOUND: + return "ERROR_FUNCTION_NOT_FOUND" + case ERROR_DEVICE_NOT_FOUND: + return "ERROR_DEVICE_NOT_FOUND" + case ERROR_NVML_LIB_CALL: + return "ERROR_NVML_LIB_CALL" + case ERROR_UNKNOWN: + return "ERROR_UNKNOWN" + default: + return fmt.Sprintf("unknown return value: %d", r) + } +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/types_gen.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/types_gen.go new file mode 100644 index 00000000..90a00ed6 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/types_gen.go @@ -0,0 +1,39 @@ +// Code generated by cmd/cgo -godefs; DO NOT EDIT. +// cgo -godefs types.go + +package nvsandboxutils + +type InitInput_v1 struct { + Version uint32 + Type uint32 + Value [256]int8 +} + +type InitInput struct { + Version uint32 + Type uint32 + Value [256]int8 +} + +type GpuFileInfo_v1 struct { + Next *GpuFileInfo_v1 + FileType uint32 + FileSubType uint32 + Module uint32 + Flags uint32 + FilePath *int8 +} + +type GpuRes_v1 struct { + Version uint32 + InputType uint32 + Input [256]int8 + Files *GpuFileInfo_v1 +} + +type GpuRes struct { + Version uint32 + InputType uint32 + Input [256]int8 + Files *GpuFileInfo_v1 +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/zz_generated.api.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/zz_generated.api.go new file mode 100644 index 00000000..631b2b05 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils/zz_generated.api.go @@ -0,0 +1,43 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +// Generated Code; DO NOT EDIT. + +package nvsandboxutils + +// The variables below represent package level methods from the library type. +var ( + ErrorString = libnvsandboxutils.ErrorString + GetDriverVersion = libnvsandboxutils.GetDriverVersion + GetFileContent = libnvsandboxutils.GetFileContent + GetGpuResource = libnvsandboxutils.GetGpuResource + Init = libnvsandboxutils.Init + LookupSymbol = libnvsandboxutils.LookupSymbol + Shutdown = libnvsandboxutils.Shutdown +) + +// Interface represents the interface for the library type. +// +//go:generate moq -rm -fmt=goimports -out mock/interface.go -pkg mock . Interface:Interface +type Interface interface { + ErrorString(Ret) string + GetDriverVersion() (string, Ret) + GetFileContent(string) (string, Ret) + GetGpuResource(string) ([]GpuFileInfo, Ret) + Init(string) Ret + LookupSymbol(string) error + Shutdown() Ret +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/args.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/args.go new file mode 100644 index 00000000..de85d9cc --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/args.go @@ -0,0 +1,115 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "fmt" + "path/filepath" + "strings" +) + +const ( + specFileName = "config.json" +) + +// GetBundleDir returns the bundle directory or default depending on the +// supplied command line arguments. +func GetBundleDir(args []string) (string, error) { + bundleDir, err := GetBundleDirFromArgs(args) + if err != nil { + return "", fmt.Errorf("error getting bundle dir from args: %v", err) + } + + return bundleDir, nil +} + +// GetBundleDirFromArgs checks the specified slice of strings (argv) for a 'bundle' flag as allowed by runc. +// The following are supported: +// --bundle{{SEP}}BUNDLE_PATH +// -bundle{{SEP}}BUNDLE_PATH +// -b{{SEP}}BUNDLE_PATH +// where {{SEP}} is either ' ' or '=' +func GetBundleDirFromArgs(args []string) (string, error) { + var bundleDir string + + for i := 0; i < len(args); i++ { + param := args[i] + + parts := strings.SplitN(param, "=", 2) + if !IsBundleFlag(parts[0]) { + continue + } + + // The flag has the format --bundle=/path + if len(parts) == 2 { + bundleDir = parts[1] + continue + } + + // The flag has the format --bundle /path + if i+1 < len(args) { + bundleDir = args[i+1] + i++ + continue + } + + // --bundle / -b was the last element of args + return "", fmt.Errorf("bundle option requires an argument") + } + + return bundleDir, nil +} + +// GetSpecFilePath returns the expected path to the OCI specification file for the given +// bundle directory. +func GetSpecFilePath(bundleDir string) string { + specFilePath := filepath.Join(bundleDir, specFileName) + return specFilePath +} + +// IsBundleFlag is a helper function that checks wither the specified argument represents +// a bundle flag (--bundle or -b) +func IsBundleFlag(arg string) bool { + if !strings.HasPrefix(arg, "-") { + return false + } + + trimmed := strings.TrimLeft(arg, "-") + return trimmed == "b" || trimmed == "bundle" +} + +// HasCreateSubcommand checks the supplied arguments for a 'create' subcommand +func HasCreateSubcommand(args []string) bool { + var previousWasBundle bool + for _, a := range args { + // We check for '--bundle create' explicitly to ensure that we + // don't inadvertently trigger a modification if the bundle directory + // is specified as `create` + if !previousWasBundle && IsBundleFlag(a) { + previousWasBundle = true + continue + } + + if !previousWasBundle && a == "create" { + return true + } + + previousWasBundle = false + } + + return false +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime.go new file mode 100644 index 00000000..6039490d --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime.go @@ -0,0 +1,26 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +// Runtime is an interface for a runtime shim. The Exec method accepts a list +// of command line arguments, and returns an error / nil. +// +//go:generate moq -rm -fmt=goimports -stub -out runtime_mock.go . Runtime +type Runtime interface { + Exec([]string) error + String() string +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_low_level.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_low_level.go new file mode 100644 index 00000000..65ae8b21 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_low_level.go @@ -0,0 +1,55 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "fmt" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" +) + +// NewLowLevelRuntime creates a Runtime that wraps a low-level runtime executable. +// The executable specified is taken from the list of supplied candidates, with the first match +// present in the PATH being selected. A logger is also specified. +func NewLowLevelRuntime(logger logger.Interface, candidates []string) (Runtime, error) { + runtimePath, err := findRuntime(logger, candidates) + if err != nil { + return nil, fmt.Errorf("error locating runtime: %v", err) + } + return NewRuntimeForPath(logger, runtimePath) +} + +// findRuntime checks elements in a list of supplied candidates for a matching executable in the PATH. +// The absolute path to the first match is returned. +func findRuntime(logger logger.Interface, candidates []string) (string, error) { + if len(candidates) == 0 { + return "", fmt.Errorf("at least one runtime candidate must be specified") + } + + locator := lookup.NewExecutableLocator(logger, "/") + for _, candidate := range candidates { + logger.Tracef("Looking for runtime binary '%v'", candidate) + targets, err := locator.Locate(candidate) + if err == nil && len(targets) > 0 { + logger.Tracef("Found runtime binary '%v'", targets) + return targets[0], nil + } + } + + return "", fmt.Errorf("no runtime binary found from candidate list: %v", candidates) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_mock.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_mock.go new file mode 100644 index 00000000..147035d4 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_mock.go @@ -0,0 +1,117 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package oci + +import ( + "sync" +) + +// Ensure, that RuntimeMock does implement Runtime. +// If this is not the case, regenerate this file with moq. +var _ Runtime = &RuntimeMock{} + +// RuntimeMock is a mock implementation of Runtime. +// +// func TestSomethingThatUsesRuntime(t *testing.T) { +// +// // make and configure a mocked Runtime +// mockedRuntime := &RuntimeMock{ +// ExecFunc: func(strings []string) error { +// panic("mock out the Exec method") +// }, +// StringFunc: func() string { +// panic("mock out the String method") +// }, +// } +// +// // use mockedRuntime in code that requires Runtime +// // and then make assertions. +// +// } +type RuntimeMock struct { + // ExecFunc mocks the Exec method. + ExecFunc func(strings []string) error + + // StringFunc mocks the String method. + StringFunc func() string + + // calls tracks calls to the methods. + calls struct { + // Exec holds details about calls to the Exec method. + Exec []struct { + // Strings is the strings argument value. + Strings []string + } + // String holds details about calls to the String method. + String []struct { + } + } + lockExec sync.RWMutex + lockString sync.RWMutex +} + +// Exec calls ExecFunc. +func (mock *RuntimeMock) Exec(strings []string) error { + callInfo := struct { + Strings []string + }{ + Strings: strings, + } + mock.lockExec.Lock() + mock.calls.Exec = append(mock.calls.Exec, callInfo) + mock.lockExec.Unlock() + if mock.ExecFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.ExecFunc(strings) +} + +// ExecCalls gets all the calls that were made to Exec. +// Check the length with: +// +// len(mockedRuntime.ExecCalls()) +func (mock *RuntimeMock) ExecCalls() []struct { + Strings []string +} { + var calls []struct { + Strings []string + } + mock.lockExec.RLock() + calls = mock.calls.Exec + mock.lockExec.RUnlock() + return calls +} + +// String calls StringFunc. +func (mock *RuntimeMock) String() string { + callInfo := struct { + }{} + mock.lockString.Lock() + mock.calls.String = append(mock.calls.String, callInfo) + mock.lockString.Unlock() + if mock.StringFunc == nil { + var ( + sOut string + ) + return sOut + } + return mock.StringFunc() +} + +// StringCalls gets all the calls that were made to String. +// Check the length with: +// +// len(mockedRuntime.StringCalls()) +func (mock *RuntimeMock) StringCalls() []struct { +} { + var calls []struct { + } + mock.lockString.RLock() + calls = mock.calls.String + mock.lockString.RUnlock() + return calls +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_modifier.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_modifier.go new file mode 100644 index 00000000..50ca42fb --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_modifier.go @@ -0,0 +1,89 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "fmt" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +type modifyingRuntimeWrapper struct { + logger logger.Interface + runtime Runtime + ociSpec Spec + modifier SpecModifier +} + +var _ Runtime = (*modifyingRuntimeWrapper)(nil) + +// NewModifyingRuntimeWrapper creates a runtime wrapper that applies the specified modifier to the OCI specification +// before invoking the wrapped runtime. If the modifier is nil, the input runtime is returned. +func NewModifyingRuntimeWrapper(logger logger.Interface, runtime Runtime, spec Spec, modifier SpecModifier) Runtime { + if modifier == nil { + logger.Tracef("Using low-level runtime with no modification") + return runtime + } + + rt := modifyingRuntimeWrapper{ + logger: logger, + runtime: runtime, + ociSpec: spec, + modifier: modifier, + } + return &rt +} + +// Exec checks whether a modification of the OCI specification is required and modifies it accordingly before exec-ing +// into the wrapped runtime. +func (r *modifyingRuntimeWrapper) Exec(args []string) error { + if HasCreateSubcommand(args) { + r.logger.Debugf("Create command detected; applying OCI specification modifications") + err := r.modify() + if err != nil { + return fmt.Errorf("could not apply required modification to OCI specification: %w", err) + } + r.logger.Debugf("Applied required modification to OCI specification") + } + + r.logger.Debugf("Forwarding command to runtime %v", r.runtime.String()) + return r.runtime.Exec(args) +} + +// modify loads, modifies, and flushes the OCI specification using the defined Modifier +func (r *modifyingRuntimeWrapper) modify() error { + _, err := r.ociSpec.Load() + if err != nil { + return fmt.Errorf("error loading OCI specification for modification: %v", err) + } + + err = r.ociSpec.Modify(r.modifier) + if err != nil { + return fmt.Errorf("error modifying OCI spec: %v", err) + } + + err = r.ociSpec.Flush() + if err != nil { + return fmt.Errorf("error writing modified OCI specification: %v", err) + } + return nil +} + +// String returns a string representation of the runtime. +func (r *modifyingRuntimeWrapper) String() string { + return fmt.Sprintf("modify on-create and forward to %s", r.runtime.String()) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_path.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_path.go new file mode 100644 index 00000000..8c15a107 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_path.go @@ -0,0 +1,70 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "fmt" + "os" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +// pathRuntime wraps the path that a binary and defines the semantics for how to exec into it. +// This can be used to wrap an OCI-compliant low-level runtime binary, allowing it to be used through the +// Runtime internface. +type pathRuntime struct { + logger logger.Interface + path string + execRuntime Runtime +} + +var _ Runtime = (*pathRuntime)(nil) + +// NewRuntimeForPath creates a Runtime for the specified logger and path +func NewRuntimeForPath(logger logger.Interface, path string) (Runtime, error) { + info, err := os.Stat(path) + if err != nil { + return nil, fmt.Errorf("invalid path '%v': %v", path, err) + } + if info.IsDir() || info.Mode()&0111 == 0 { + return nil, fmt.Errorf("specified path '%v' is not an executable file", path) + } + + shim := pathRuntime{ + logger: logger, + path: path, + execRuntime: syscallExec{}, + } + + return &shim, nil +} + +// Exec exces into the binary at the path from the pathRuntime struct, passing it the supplied arguments +// after ensuring that the first argument is the path of the target binary. +func (s pathRuntime) Exec(args []string) error { + runtimeArgs := []string{s.path} + if len(args) > 1 { + runtimeArgs = append(runtimeArgs, args[1:]...) + } + + return s.execRuntime.Exec(runtimeArgs) +} + +// String returns the path to the specified runtime as the string representation. +func (s pathRuntime) String() string { + return s.path +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_syscall_exec.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_syscall_exec.go new file mode 100644 index 00000000..349edf86 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/runtime_syscall_exec.go @@ -0,0 +1,43 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "fmt" + "os" + "syscall" +) + +type syscallExec struct{} + +var _ Runtime = (*syscallExec)(nil) + +func (r syscallExec) Exec(args []string) error { + //nolint:gosec // TODO: Can we harden this so that there is less risk of command injection + err := syscall.Exec(args[0], args, os.Environ()) + if err != nil { + return fmt.Errorf("could not exec '%v': %v", args[0], err) + } + + // syscall.Exec is not expected to return. This is an error state regardless of whether + // err is nil or not. + return fmt.Errorf("unexpected return from exec '%v'", args[0]) +} + +func (r syscallExec) String() string { + return "exec" +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec.go new file mode 100644 index 00000000..1e2c144a --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec.go @@ -0,0 +1,78 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "fmt" + + "github.com/opencontainers/runtime-spec/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +// SpecModifier defines an interface for modifying a (raw) OCI spec +type SpecModifier interface { + // Modify is a method that accepts a pointer to an OCI Spec and returns an + // error. The intention is that the function would modify the spec in-place. + Modify(*specs.Spec) error +} + +// SpecModifiers is a collection of OCI Spec modifiers that can be treated as a +// single modifier. +type SpecModifiers []SpecModifier + +var _ SpecModifier = (SpecModifiers)(nil) + +// Spec defines the operations to be performed on an OCI specification +// +//go:generate moq -rm -fmt=goimports -stub -out spec_mock.go . Spec +type Spec interface { + Load() (*specs.Spec, error) + Flush() error + Modify(SpecModifier) error + LookupEnv(string) (string, bool) +} + +// NewSpec creates fileSpec based on the command line arguments passed to the +// application using the specified logger. +func NewSpec(logger logger.Interface, args []string) (Spec, error) { + bundleDir, err := GetBundleDir(args) + if err != nil { + return nil, fmt.Errorf("error getting bundle directory: %v", err) + } + logger.Debugf("Using bundle directory: %v", bundleDir) + + ociSpecPath := GetSpecFilePath(bundleDir) + logger.Infof("Using OCI specification file path: %v", ociSpecPath) + + ociSpec := NewFileSpec(ociSpecPath) + + return ociSpec, nil +} + +// Modify a spec based on a collection of modifiers. +func (ms SpecModifiers) Modify(s *specs.Spec) error { + for _, m := range ms { + if m == nil { + continue + } + if err := m.Modify(s); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec_file.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec_file.go new file mode 100644 index 00000000..8784ae92 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec_file.go @@ -0,0 +1,111 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "encoding/json" + "fmt" + "io" + "os" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +type fileSpec struct { + memorySpec + path string +} + +var _ Spec = (*fileSpec)(nil) + +// NewFileSpec creates an object that encapsulates a file-backed OCI spec. +// This can be used to read from the file, modify the spec, and write to the +// same file. +func NewFileSpec(filepath string) Spec { + oci := fileSpec{ + path: filepath, + } + + return &oci +} + +// Load reads the contents of an OCI spec from file to be referenced internally. +// The file is opened "read-only" +func (s *fileSpec) Load() (*specs.Spec, error) { + specFile, err := os.Open(s.path) + if err != nil { + return nil, fmt.Errorf("error opening OCI specification file: %v", err) + } + defer specFile.Close() + + spec, err := LoadFrom(specFile) + if err != nil { + return nil, fmt.Errorf("error loading OCI specification from file: %v", err) + } + s.Spec = spec + return s.Spec, nil +} + +// LoadFrom reads the contents of the OCI spec from the specified io.Reader. +func LoadFrom(reader io.Reader) (*specs.Spec, error) { + decoder := json.NewDecoder(reader) + + var spec specs.Spec + + err := decoder.Decode(&spec) + if err != nil { + return nil, fmt.Errorf("error reading OCI specification: %v", err) + } + + return &spec, nil +} + +// Modify applies the specified SpecModifier to the stored OCI specification. +func (s *fileSpec) Modify(m SpecModifier) error { + return s.memorySpec.Modify(m) +} + +// Flush writes the stored OCI specification to the filepath specified by the path member. +// The file is truncated upon opening, overwriting any existing contents. +func (s fileSpec) Flush() error { + if s.Spec == nil { + return fmt.Errorf("no OCI specification loaded") + } + + specFile, err := os.Create(s.path) + if err != nil { + return fmt.Errorf("error opening OCI specification file: %v", err) + } + defer specFile.Close() + + return flushTo(s.Spec, specFile) +} + +// flushTo writes the stored OCI specification to the specified io.Writer. +func flushTo(spec *specs.Spec, writer io.Writer) error { + if spec == nil { + return nil + } + encoder := json.NewEncoder(writer) + + err := encoder.Encode(spec) + if err != nil { + return fmt.Errorf("error writing OCI specification: %v", err) + } + + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec_memory.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec_memory.go new file mode 100644 index 00000000..fd27bdad --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec_memory.go @@ -0,0 +1,83 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package oci + +import ( + "fmt" + "strings" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +type memorySpec struct { + *specs.Spec +} + +// NewMemorySpec creates a Spec instance from the specified OCI spec +func NewMemorySpec(spec *specs.Spec) Spec { + s := memorySpec{ + Spec: spec, + } + + return &s +} + +// Load is a no-op for the memorySpec spec +func (s *memorySpec) Load() (*specs.Spec, error) { + return s.Spec, nil +} + +// Flush is a no-op for the memorySpec spec +func (s *memorySpec) Flush() error { + return nil +} + +// Modify applies the specified SpecModifier to the stored OCI specification. +func (s *memorySpec) Modify(m SpecModifier) error { + if s.Spec == nil { + return fmt.Errorf("cannot modify nil spec") + } + return m.Modify(s.Spec) +} + +// LookupEnv mirrors os.LookupEnv for the OCI specification. It +// retrieves the value of the environment variable named +// by the key. If the variable is present in the environment the +// value (which may be empty) is returned and the boolean is true. +// Otherwise the returned value will be empty and the boolean will +// be false. +func (s memorySpec) LookupEnv(key string) (string, bool) { + if s.Spec == nil || s.Process == nil { + return "", false + } + + for _, env := range s.Process.Env { + if !strings.HasPrefix(env, key) { + continue + } + + parts := strings.SplitN(env, "=", 2) + if parts[0] == key { + if len(parts) < 2 { + return "", true + } + return parts[1], true + } + } + + return "", false +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec_mock.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec_mock.go new file mode 100644 index 00000000..f004d69c --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/spec_mock.go @@ -0,0 +1,208 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package oci + +import ( + "sync" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +// Ensure, that SpecMock does implement Spec. +// If this is not the case, regenerate this file with moq. +var _ Spec = &SpecMock{} + +// SpecMock is a mock implementation of Spec. +// +// func TestSomethingThatUsesSpec(t *testing.T) { +// +// // make and configure a mocked Spec +// mockedSpec := &SpecMock{ +// FlushFunc: func() error { +// panic("mock out the Flush method") +// }, +// LoadFunc: func() (*specs.Spec, error) { +// panic("mock out the Load method") +// }, +// LookupEnvFunc: func(s string) (string, bool) { +// panic("mock out the LookupEnv method") +// }, +// ModifyFunc: func(specModifier SpecModifier) error { +// panic("mock out the Modify method") +// }, +// } +// +// // use mockedSpec in code that requires Spec +// // and then make assertions. +// +// } +type SpecMock struct { + // FlushFunc mocks the Flush method. + FlushFunc func() error + + // LoadFunc mocks the Load method. + LoadFunc func() (*specs.Spec, error) + + // LookupEnvFunc mocks the LookupEnv method. + LookupEnvFunc func(s string) (string, bool) + + // ModifyFunc mocks the Modify method. + ModifyFunc func(specModifier SpecModifier) error + + // calls tracks calls to the methods. + calls struct { + // Flush holds details about calls to the Flush method. + Flush []struct { + } + // Load holds details about calls to the Load method. + Load []struct { + } + // LookupEnv holds details about calls to the LookupEnv method. + LookupEnv []struct { + // S is the s argument value. + S string + } + // Modify holds details about calls to the Modify method. + Modify []struct { + // SpecModifier is the specModifier argument value. + SpecModifier SpecModifier + } + } + lockFlush sync.RWMutex + lockLoad sync.RWMutex + lockLookupEnv sync.RWMutex + lockModify sync.RWMutex +} + +// Flush calls FlushFunc. +func (mock *SpecMock) Flush() error { + callInfo := struct { + }{} + mock.lockFlush.Lock() + mock.calls.Flush = append(mock.calls.Flush, callInfo) + mock.lockFlush.Unlock() + if mock.FlushFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.FlushFunc() +} + +// FlushCalls gets all the calls that were made to Flush. +// Check the length with: +// +// len(mockedSpec.FlushCalls()) +func (mock *SpecMock) FlushCalls() []struct { +} { + var calls []struct { + } + mock.lockFlush.RLock() + calls = mock.calls.Flush + mock.lockFlush.RUnlock() + return calls +} + +// Load calls LoadFunc. +func (mock *SpecMock) Load() (*specs.Spec, error) { + callInfo := struct { + }{} + mock.lockLoad.Lock() + mock.calls.Load = append(mock.calls.Load, callInfo) + mock.lockLoad.Unlock() + if mock.LoadFunc == nil { + var ( + specOut *specs.Spec + errOut error + ) + return specOut, errOut + } + return mock.LoadFunc() +} + +// LoadCalls gets all the calls that were made to Load. +// Check the length with: +// +// len(mockedSpec.LoadCalls()) +func (mock *SpecMock) LoadCalls() []struct { +} { + var calls []struct { + } + mock.lockLoad.RLock() + calls = mock.calls.Load + mock.lockLoad.RUnlock() + return calls +} + +// LookupEnv calls LookupEnvFunc. +func (mock *SpecMock) LookupEnv(s string) (string, bool) { + callInfo := struct { + S string + }{ + S: s, + } + mock.lockLookupEnv.Lock() + mock.calls.LookupEnv = append(mock.calls.LookupEnv, callInfo) + mock.lockLookupEnv.Unlock() + if mock.LookupEnvFunc == nil { + var ( + sOut string + bOut bool + ) + return sOut, bOut + } + return mock.LookupEnvFunc(s) +} + +// LookupEnvCalls gets all the calls that were made to LookupEnv. +// Check the length with: +// +// len(mockedSpec.LookupEnvCalls()) +func (mock *SpecMock) LookupEnvCalls() []struct { + S string +} { + var calls []struct { + S string + } + mock.lockLookupEnv.RLock() + calls = mock.calls.LookupEnv + mock.lockLookupEnv.RUnlock() + return calls +} + +// Modify calls ModifyFunc. +func (mock *SpecMock) Modify(specModifier SpecModifier) error { + callInfo := struct { + SpecModifier SpecModifier + }{ + SpecModifier: specModifier, + } + mock.lockModify.Lock() + mock.calls.Modify = append(mock.calls.Modify, callInfo) + mock.lockModify.Unlock() + if mock.ModifyFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.ModifyFunc(specModifier) +} + +// ModifyCalls gets all the calls that were made to Modify. +// Check the length with: +// +// len(mockedSpec.ModifyCalls()) +func (mock *SpecMock) ModifyCalls() []struct { + SpecModifier SpecModifier +} { + var calls []struct { + SpecModifier SpecModifier + } + mock.lockModify.RLock() + calls = mock.calls.Modify + mock.lockModify.RUnlock() + return calls +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/state.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/state.go new file mode 100644 index 00000000..2bb4e6e5 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/oci/state.go @@ -0,0 +1,93 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package oci + +import ( + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +// State stores an OCI container state. This includes the spec path and the environment +type State specs.State + +// LoadContainerState loads the container state from the specified filename. If the filename is empty or '-' the state is loaded from STDIN +func LoadContainerState(filename string) (*State, error) { + if filename == "" || filename == "-" { + return ReadContainerState(os.Stdin) + } + + inputFile, err := os.Open(filename) + if err != nil { + return nil, fmt.Errorf("failed to open file: %v", err) + } + defer inputFile.Close() + + return ReadContainerState(inputFile) +} + +// ReadContainerState reads the container state from the specified reader +func ReadContainerState(reader io.Reader) (*State, error) { + var s State + + d := json.NewDecoder(reader) + if err := d.Decode(&s); err != nil { + return nil, fmt.Errorf("failed to decode container state: %v", err) + } + + return &s, nil +} + +// LoadSpec loads the OCI spec associated with the container state +func (s *State) LoadSpec() (*specs.Spec, error) { + specFilePath := GetSpecFilePath(s.Bundle) + specFile, err := os.Open(specFilePath) + if err != nil { + return nil, fmt.Errorf("failed to open OCI spec file: %v", err) + } + defer specFile.Close() + + spec, err := LoadFrom(specFile) + if err != nil { + return nil, fmt.Errorf("failed to load OCI spec: %v", err) + } + return spec, nil +} + +// GetContainerRoot returns the root for the container from the associated spec. If the spec is not yet loaded, it is +// loaded and cached. +func (s *State) GetContainerRoot() (string, error) { + spec, err := s.LoadSpec() + if err != nil { + return "", err + } + + var containerRoot string + if spec.Root != nil { + containerRoot = spec.Root.Path + } + + if filepath.IsAbs(containerRoot) { + return containerRoot, nil + } + + return filepath.Join(s.Bundle, containerRoot), nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/by-path-hooks.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/by-path-hooks.go new file mode 100644 index 00000000..935d831b --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/by-path-hooks.go @@ -0,0 +1,113 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package dgpu + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +// byPathHookDiscoverer discovers the entities required for injecting by-path DRM device links +type byPathHookDiscoverer struct { + logger logger.Interface + devRoot string + hookCreator discover.HookCreator + pciBusID string + deviceNodes discover.Discover +} + +var _ discover.Discover = (*byPathHookDiscoverer)(nil) + +// Devices returns the empty list for the by-path hook discoverer +func (d *byPathHookDiscoverer) Devices() ([]discover.Device, error) { + return nil, nil +} + +// EnvVars returns the empty list for the by-path hook discoverer +func (d *byPathHookDiscoverer) EnvVars() ([]discover.EnvVar, error) { + return nil, nil +} + +// Hooks returns the hooks for the GPU device. +// The following hooks are detected: +// 1. A hook to create /dev/dri/by-path symlinks +func (d *byPathHookDiscoverer) Hooks() ([]discover.Hook, error) { + links, err := d.deviceNodeLinks() + if err != nil { + return nil, fmt.Errorf("failed to discover DRA device links: %v", err) + } + if len(links) == 0 { + return nil, nil + } + + hook := d.hookCreator.Create("create-symlinks", links...) + + return hook.Hooks() +} + +// Mounts returns an empty slice for a full GPU +func (d *byPathHookDiscoverer) Mounts() ([]discover.Mount, error) { + return nil, nil +} + +func (d *byPathHookDiscoverer) deviceNodeLinks() ([]string, error) { + devices, err := d.deviceNodes.Devices() + if err != nil { + return nil, fmt.Errorf("failed to discover device nodes: %v", err) + } + + if len(devices) == 0 { + return nil, nil + } + + selectedDevices := make(map[string]bool) + for _, d := range devices { + selectedDevices[d.HostPath] = true + } + + candidates := []string{ + fmt.Sprintf("/dev/dri/by-path/pci-%s-card", d.pciBusID), + fmt.Sprintf("/dev/dri/by-path/pci-%s-render", d.pciBusID), + } + + var links []string + for _, c := range candidates { + linkPath := filepath.Join(d.devRoot, c) + device, err := os.Readlink(linkPath) + if err != nil { + d.logger.Warningf("Failed to evaluate symlink %v; ignoring", linkPath) + continue + } + + deviceNode := device + if !filepath.IsAbs(device) { + deviceNode = filepath.Join(filepath.Dir(linkPath), device) + } + if !selectedDevices[deviceNode] { + d.logger.Debugf("ignoring device symlink %v -> %v since %v is not mounted", linkPath, device, deviceNode) + continue + } + d.logger.Debugf("adding device symlink %v -> %v", linkPath, device) + links = append(links, fmt.Sprintf("%v::%v", device, linkPath)) + } + + return links, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/dgpu.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/dgpu.go new file mode 100644 index 00000000..de411bd6 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/dgpu.go @@ -0,0 +1,125 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package dgpu + +import ( + "errors" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/device" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/nvcaps" +) + +// NewForDevice creates a discoverer for the specified Device. +// nvsandboxutils is used for discovery if specified, otherwise NVML is used. +func NewForDevice(d device.Device, opts ...Option) (discover.Discover, error) { + o := new(opts...) + + var discoverers []discover.Discover + var errs error + nvsandboxutilsDiscoverer, err := o.newNvsandboxutilsDGPUDiscoverer(d) + if err != nil { + // TODO: Log a warning + errs = errors.Join(errs, err) + } else if nvsandboxutilsDiscoverer != nil { + discoverers = append(discoverers, nvsandboxutilsDiscoverer) + } + + nvmlDiscoverer, err := o.newNvmlDGPUDiscoverer(&toRequiredInfo{d}) + if err != nil { + // TODO: Log a warning + errs = errors.Join(errs, err) + } else if nvmlDiscoverer != nil { + discoverers = append(discoverers, nvmlDiscoverer) + } + + if len(discoverers) == 0 { + return nil, errs + } + + return discover.WithCache( + discover.FirstValid( + discoverers..., + ), + ), nil +} + +// NewForMigDevice creates a discoverer for the specified device and its associated MIG device. +// nvsandboxutils is used for discovery if specified, otherwise NVML is used. +func NewForMigDevice(d device.Device, mig device.MigDevice, opts ...Option) (discover.Discover, error) { + o := new(opts...) + o.isMigDevice = true + + var discoverers []discover.Discover + var errs error + nvsandboxutilsDiscoverer, err := o.newNvsandboxutilsDGPUDiscoverer(mig) + if err != nil { + // TODO: Log a warning + errs = errors.Join(errs, err) + } else if nvsandboxutilsDiscoverer != nil { + discoverers = append(discoverers, nvsandboxutilsDiscoverer) + } + + nvmlDiscoverer, err := o.newNvmlMigDiscoverer( + &toRequiredMigInfo{ + MigDevice: mig, + parent: &toRequiredInfo{d}, + }, + ) + if err != nil { + // TODO: Log a warning + errs = errors.Join(errs, err) + } else if nvmlDiscoverer != nil { + discoverers = append(discoverers, nvmlDiscoverer) + } + + if len(discoverers) == 0 { + return nil, errs + } + + return discover.WithCache( + discover.FirstValid( + discoverers..., + ), + ), nil + +} + +func new(opts ...Option) *options { + o := &options{} + for _, opt := range opts { + opt(o) + } + + if o.logger == nil { + o.logger = logger.New() + } + + if o.migCaps == nil { + migCaps, err := nvcaps.NewMigCaps() + if err != nil { + o.logger.Debugf("ignoring error getting MIG capability device paths: %v", err) + o.migCapsError = err + } else { + o.migCaps = migCaps + } + } + + return o +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/nvml.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/nvml.go new file mode 100644 index 00000000..2ad36a24 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/nvml.go @@ -0,0 +1,167 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package dgpu + +import ( + "fmt" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/device" + "github.com/NVIDIA/go-nvml/pkg/nvml" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/info/drm" + "github.com/NVIDIA/nvidia-container-toolkit/internal/nvcaps" +) + +type requiredInfo interface { + GetMinorNumber() (int, error) + GetPCIBusID() (string, error) + getDevNodePath() (string, error) +} + +func (o *options) newNvmlDGPUDiscoverer(d requiredInfo) (discover.Discover, error) { + path, err := d.getDevNodePath() + if err != nil { + return nil, fmt.Errorf("error getting device node path: %w", err) + } + + pciBusID, err := d.GetPCIBusID() + if err != nil { + return nil, fmt.Errorf("error getting PCI info for device: %w", err) + } + + drmDeviceNodes, err := drm.GetDeviceNodesByBusID(pciBusID) + if err != nil { + return nil, fmt.Errorf("failed to determine DRM devices for %v: %v", pciBusID, err) + } + + deviceNodePaths := append([]string{path}, drmDeviceNodes...) + + deviceNodes := discover.NewCharDeviceDiscoverer( + o.logger, + o.devRoot, + deviceNodePaths, + ) + + byPathHooks := &byPathHookDiscoverer{ + logger: o.logger, + devRoot: o.devRoot, + hookCreator: o.hookCreator, + pciBusID: pciBusID, + deviceNodes: deviceNodes, + } + + dd := discover.Merge( + deviceNodes, + byPathHooks, + ) + return dd, nil +} + +type requiredMigInfo interface { + getPlacementInfo() (int, int, int, error) + getDevNodePath() (string, error) +} + +func (o *options) newNvmlMigDiscoverer(d requiredMigInfo) (discover.Discover, error) { + if o.migCaps == nil || o.migCapsError != nil { + return nil, fmt.Errorf("error getting MIG capability device paths: %v", o.migCapsError) + } + + gpu, gi, ci, err := d.getPlacementInfo() + if err != nil { + return nil, fmt.Errorf("error getting placement info: %w", err) + } + + giCap := nvcaps.NewGPUInstanceCap(gpu, gi) + giCapDevicePath, err := o.migCaps.GetCapDevicePath(giCap) + if err != nil { + return nil, fmt.Errorf("failed to get GI cap device path: %v", err) + } + + ciCap := nvcaps.NewComputeInstanceCap(gpu, gi, ci) + ciCapDevicePath, err := o.migCaps.GetCapDevicePath(ciCap) + if err != nil { + return nil, fmt.Errorf("failed to get CI cap device path: %v", err) + } + + parentPath, err := d.getDevNodePath() + if err != nil { + return nil, err + } + + deviceNodes := discover.NewCharDeviceDiscoverer( + o.logger, + o.devRoot, + []string{ + parentPath, + giCapDevicePath, + ciCapDevicePath, + }, + ) + + return deviceNodes, nil +} + +type toRequiredInfo struct { + device.Device +} + +func (d *toRequiredInfo) GetMinorNumber() (int, error) { + minor, ret := d.Device.GetMinorNumber() + if ret != nvml.SUCCESS { + return 0, ret + } + return minor, nil +} + +func (d *toRequiredInfo) getDevNodePath() (string, error) { + minor, err := d.GetMinorNumber() + if err != nil { + return "", fmt.Errorf("error getting GPU device minor number: %w", err) + } + path := fmt.Sprintf("/dev/nvidia%d", minor) + return path, nil +} + +type toRequiredMigInfo struct { + device.MigDevice + parent requiredInfo +} + +func (d *toRequiredMigInfo) getPlacementInfo() (int, int, int, error) { + gpu, err := d.parent.GetMinorNumber() + if err != nil { + return 0, 0, 0, fmt.Errorf("error getting GPU minor: %w", err) + } + + gi, ret := d.GetGpuInstanceId() + if ret != nvml.SUCCESS { + return 0, 0, 0, fmt.Errorf("error getting GPU Instance ID: %v", ret) + } + + ci, ret := d.GetComputeInstanceId() + if ret != nvml.SUCCESS { + return 0, 0, 0, fmt.Errorf("error getting Compute Instance ID: %v", ret) + } + + return gpu, gi, ci, nil +} + +func (d *toRequiredMigInfo) getDevNodePath() (string, error) { + return d.parent.getDevNodePath() +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/nvsandboxutils.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/nvsandboxutils.go new file mode 100644 index 00000000..9345f63a --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/nvsandboxutils.go @@ -0,0 +1,126 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package dgpu + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/NVIDIA/go-nvml/pkg/nvml" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils" +) + +type nvsandboxutilsDGPU struct { + lib nvsandboxutils.Interface + uuid string + devRoot string + isMig bool + hookCreator discover.HookCreator + deviceLinks []string +} + +var _ discover.Discover = (*nvsandboxutilsDGPU)(nil) + +type UUIDer interface { + GetUUID() (string, nvml.Return) +} + +func (o *options) newNvsandboxutilsDGPUDiscoverer(d UUIDer) (discover.Discover, error) { + if o.nvsandboxutilslib == nil { + return nil, nil + } + + uuid, nvmlRet := d.GetUUID() + if nvmlRet != nvml.SUCCESS { + return nil, fmt.Errorf("failed to get device UUID: %w", nvmlRet) + } + + nvd := nvsandboxutilsDGPU{ + lib: o.nvsandboxutilslib, + uuid: uuid, + devRoot: strings.TrimSuffix(filepath.Clean(o.devRoot), "/dev"), + isMig: o.isMigDevice, + hookCreator: o.hookCreator, + } + + return &nvd, nil +} + +func (d *nvsandboxutilsDGPU) Devices() ([]discover.Device, error) { + gpuFileInfos, ret := d.lib.GetGpuResource(d.uuid) + if ret != nvsandboxutils.SUCCESS { + return nil, fmt.Errorf("failed to get GPU resource: %w", ret) + } + + var devices []discover.Device + for _, info := range gpuFileInfos { + switch info.SubType { + case nvsandboxutils.NV_DEV_DRI_CARD, nvsandboxutils.NV_DEV_DRI_RENDERD: + if d.isMig { + continue + } + fallthrough + case nvsandboxutils.NV_DEV_NVIDIA, nvsandboxutils.NV_DEV_NVIDIA_CAPS_NVIDIA_CAP: + containerPath := info.Path + if d.devRoot != "/" { + containerPath = strings.TrimPrefix(containerPath, d.devRoot) + } + + // TODO: Extend discover.Device with additional information. + device := discover.Device{ + HostPath: info.Path, + Path: containerPath, + } + devices = append(devices, device) + case nvsandboxutils.NV_DEV_DRI_CARD_SYMLINK, nvsandboxutils.NV_DEV_DRI_RENDERD_SYMLINK: + if d.isMig { + continue + } + if info.Flags == nvsandboxutils.NV_FILE_FLAG_CONTENT { + targetPath, ret := d.lib.GetFileContent(info.Path) + if ret != nvsandboxutils.SUCCESS { + return nil, fmt.Errorf("failed to get symlink: %w", ret) + } + d.deviceLinks = append(d.deviceLinks, fmt.Sprintf("%v::%v", targetPath, info.Path)) + } + } + } + + return devices, nil +} + +func (d *nvsandboxutilsDGPU) EnvVars() ([]discover.EnvVar, error) { + return nil, nil +} + +// Hooks returns a hook to create the by-path symlinks for the discovered devices. +func (d *nvsandboxutilsDGPU) Hooks() ([]discover.Hook, error) { + if len(d.deviceLinks) == 0 { + return nil, nil + } + + hook := d.hookCreator.Create("create-symlinks", d.deviceLinks...) + + return hook.Hooks() +} + +func (d *nvsandboxutilsDGPU) Mounts() ([]discover.Mount, error) { + return nil, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/options.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/options.go new file mode 100644 index 00000000..6b2d62ce --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu/options.go @@ -0,0 +1,75 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package dgpu + +import ( + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/nvcaps" + "github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils" +) + +type options struct { + logger logger.Interface + devRoot string + hookCreator discover.HookCreator + + isMigDevice bool + // migCaps stores the MIG capabilities for the system. + // If MIG is not available, this is nil. + migCaps nvcaps.MigCaps + migCapsError error + + nvsandboxutilslib nvsandboxutils.Interface +} + +type Option func(*options) + +// WithDevRoot sets the root where /dev is located. +func WithDevRoot(root string) Option { + return func(l *options) { + l.devRoot = root + } +} + +// WithLogger sets the logger for the library +func WithLogger(logger logger.Interface) Option { + return func(l *options) { + l.logger = logger + } +} + +// WithHookCreator sets the hook creator for the library +func WithHookCreator(hookCreator discover.HookCreator) Option { + return func(l *options) { + l.hookCreator = hookCreator + } +} + +// WithMIGCaps sets the MIG capabilities. +func WithMIGCaps(migCaps nvcaps.MigCaps) Option { + return func(l *options) { + l.migCaps = migCaps + } +} + +// WithNvsandboxuitilsLib sets the nvsandboxutils library implementation. +func WithNvsandboxuitilsLib(nvsandboxutilslib nvsandboxutils.Interface) Option { + return func(l *options) { + l.nvsandboxutilslib = nvsandboxutilslib + } +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv.go new file mode 100644 index 00000000..edb7fdc4 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv.go @@ -0,0 +1,119 @@ +/** +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package tegra + +import ( + "fmt" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" + "github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv" +) + +// newDiscovererFromCSVFiles creates a discoverer for the specified CSV files. A logger is also supplied. +// The constructed discoverer is comprised of a list, with each element in the list being associated with a +// single CSV files. +func (o tegraOptions) newDiscovererFromCSVFiles() (discover.Discover, error) { + if len(o.csvFiles) == 0 { + o.logger.Warningf("No CSV files specified") + return discover.None{}, nil + } + + targetsByType := getTargetsFromCSVFiles(o.logger, o.csvFiles) + + devices := discover.NewCharDeviceDiscoverer( + o.logger, + o.devRoot, + targetsByType[csv.MountSpecDev], + ) + + directories := discover.NewMounts( + o.logger, + lookup.NewDirectoryLocator(lookup.WithLogger(o.logger), lookup.WithRoot(o.driverRoot)), + o.driverRoot, + targetsByType[csv.MountSpecDir], + ) + + // We create a discoverer for mounted libraries and add additional .so + // symlinks for the driver. + libraries := discover.WithDriverDotSoSymlinks( + o.logger, + discover.NewMounts( + o.logger, + o.symlinkLocator, + o.driverRoot, + targetsByType[csv.MountSpecLib], + ), + "", + o.hookCreator, + ) + + // We process the explicitly requested symlinks. + symlinkTargets := o.ignorePatterns.Apply(targetsByType[csv.MountSpecSym]...) + o.logger.Debugf("Filtered symlink targets: %v", symlinkTargets) + symlinks := discover.NewMounts( + o.logger, + o.symlinkLocator, + o.driverRoot, + symlinkTargets, + ) + createSymlinks := o.createCSVSymlinkHooks(symlinkTargets) + + d := discover.Merge( + devices, + directories, + libraries, + symlinks, + createSymlinks, + ) + + return d, nil +} + +// getTargetsFromCSVFiles returns the list of mount specs from the specified CSV files. +// These are aggregated by mount spec type. +// TODO: We use a function variable here to allow this to be overridden for testing. +// This should be properly mocked. +var getTargetsFromCSVFiles = func(logger logger.Interface, files []string) map[csv.MountSpecType][]string { + targetsByType := make(map[csv.MountSpecType][]string) + for _, filename := range files { + targets, err := loadCSVFile(logger, filename) + if err != nil { + logger.Warningf("Skipping CSV file %v: %v", filename, err) + continue + } + for _, t := range targets { + targetsByType[t.Type] = append(targetsByType[t.Type], t.Path) + } + } + return targetsByType +} + +// loadCSVFile loads the specified CSV file and returns the list of mount specs +func loadCSVFile(logger logger.Interface, filename string) ([]*csv.MountSpec, error) { + // Create a discoverer for each file-kind combination + targets, err := csv.NewCSVFileParser(logger, filename).Parse() + if err != nil { + return nil, fmt.Errorf("failed to parse CSV file: %v", err) + } + if len(targets) == 0 { + return nil, fmt.Errorf("CSV file is empty") + } + + return targets, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv/csv.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv/csv.go new file mode 100644 index 00000000..c4f6f495 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv/csv.go @@ -0,0 +1,147 @@ +/** +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package csv + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +const ( + // DefaultMountSpecPath is default location of CSV files that define the modifications required to the OCI spec + DefaultMountSpecPath = "/etc/nvidia-container-runtime/host-files-for-container.d" +) + +// DefaultFileList returns the list of CSV files that are used by default. +func DefaultFileList() []string { + files := []string{ + "devices.csv", + "drivers.csv", + "l4t.csv", + } + + var paths []string + for _, file := range files { + paths = append(paths, filepath.Join(DefaultMountSpecPath, file)) + } + + return paths +} + +// GetFileList returns the (non-recursive) list of CSV files in the specified +// folder +func GetFileList(root string) ([]string, error) { + contents, err := os.ReadDir(root) + if err != nil && errors.Is(err, os.ErrNotExist) { + return nil, nil + } else if err != nil { + return nil, fmt.Errorf("failed to read the contents of %v: %v", root, err) + } + + var csvFilePaths []string + for _, c := range contents { + if c.IsDir() { + continue + } + if c.Name() == ".csv" { + continue + } + ext := strings.ToLower(filepath.Ext(c.Name())) + if ext != ".csv" { + continue + } + + csvFilePaths = append(csvFilePaths, filepath.Join(root, c.Name())) + } + + return csvFilePaths, nil +} + +// BaseFilesOnly filters out non-base CSV files from the list of CSV files. +func BaseFilesOnly(filenames []string) []string { + filter := map[string]bool{ + "l4t.csv": true, + "drivers.csv": true, + "devices.csv": true, + } + + var selected []string + for _, file := range filenames { + base := filepath.Base(file) + if filter[base] { + selected = append(selected, file) + } + } + + return selected +} + +// Parser specifies an interface for parsing MountSpecs +type Parser interface { + Parse() ([]*MountSpec, error) +} + +type csv struct { + logger logger.Interface + filename string +} + +// NewCSVFileParser creates a new parser for reading MountSpecs from the specified CSV file +func NewCSVFileParser(logger logger.Interface, filename string) Parser { + p := csv{ + logger: logger, + filename: filename, + } + + return &p +} + +// Parse parses the csv file and returns a list of MountSpecs in the file +func (p csv) Parse() ([]*MountSpec, error) { + reader, err := os.Open(p.filename) + if err != nil { + return nil, fmt.Errorf("failed to open %v for reading: %v", p.filename, err) + } + defer reader.Close() + + return p.parseFromReader(reader), nil +} + +// parseFromReader parses the specified file and returns a list of required jetson mounts +func (p csv) parseFromReader(reader io.Reader) []*MountSpec { + var targets []*MountSpec + + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + line := scanner.Text() + target, err := NewMountSpecFromLine(line) + if err != nil { + p.logger.Debugf("Skipping invalid mount spec '%v': %v", line, err) + continue + } + targets = append(targets, target) + } + + return targets +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv/mount_spec.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv/mount_spec.go new file mode 100644 index 00000000..3ab5f9bf --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv/mount_spec.go @@ -0,0 +1,74 @@ +/** +# Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package csv + +import ( + "fmt" + "strings" +) + +// MountSpecType defines the mount types allowed in a CSV file +type MountSpecType string + +const ( + // MountSpecDev is used for character devices + MountSpecDev = MountSpecType("dev") + // MountSpecDir is used for directories + MountSpecDir = MountSpecType("dir") + // MountSpecLib is used for libraries or regular files + MountSpecLib = MountSpecType("lib") + // MountSpecSym is used for symlinks. + MountSpecSym = MountSpecType("sym") +) + +// MountSpec represents a Jetson mount consisting of a type and a path. +type MountSpec struct { + Type MountSpecType + Path string +} + +// NewMountSpecFromLine parses the specified line and returns the MountSpec or an error if the line is malformed +func NewMountSpecFromLine(line string) (*MountSpec, error) { + parts := strings.SplitN(strings.TrimSpace(line), ",", 2) + if len(parts) < 2 { + return nil, fmt.Errorf("failed to parse line: %v", line) + } + mountType := strings.TrimSpace(parts[0]) + path := strings.TrimSpace(parts[1]) + + return NewMountSpec(mountType, path) +} + +// NewMountSpec creates a MountSpec with the specified type and path. An error is returned if the type is invalid. +func NewMountSpec(mountType string, path string) (*MountSpec, error) { + mt := MountSpecType(mountType) + switch mt { + case MountSpecDev, MountSpecLib, MountSpecSym, MountSpecDir: + default: + return nil, fmt.Errorf("unexpected mount type: %v", mt) + } + if path == "" { + return nil, fmt.Errorf("invalid path: %v", path) + } + + mount := MountSpec{ + Type: mt, + Path: path, + } + + return &mount, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/filter.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/filter.go new file mode 100644 index 00000000..03b18bf7 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/filter.go @@ -0,0 +1,49 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package tegra + +import ( + "path/filepath" + "strings" +) + +type ignoreMountSpecPatterns []string + +func (d ignoreMountSpecPatterns) Match(name string) bool { + for _, pattern := range d { + target := name + if strings.HasPrefix(pattern, "**/") { + target = filepath.Base(name) + pattern = strings.TrimPrefix(pattern, "**/") + } + if match, _ := filepath.Match(pattern, target); match { + return true + } + } + return false +} + +func (d ignoreMountSpecPatterns) Apply(input ...string) []string { + var filtered []string + for _, name := range input { + if d.Match(name) { + continue + } + filtered = append(filtered, name) + } + return filtered +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/symlinks.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/symlinks.go new file mode 100644 index 00000000..822d482f --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/symlinks.go @@ -0,0 +1,93 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package tegra + +import ( + "fmt" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" +) + +type symlinkHook struct { + discover.None + logger logger.Interface + hookCreator discover.HookCreator + targets []string + + // The following can be overridden for testing + symlinkChainLocator lookup.Locator + resolveSymlink func(string) (string, error) +} + +// createCSVSymlinkHooks creates a discoverer for a hook that creates required symlinks in the container +func (o tegraOptions) createCSVSymlinkHooks(targets []string) discover.Discover { + return symlinkHook{ + logger: o.logger, + hookCreator: o.hookCreator, + targets: targets, + symlinkChainLocator: o.symlinkChainLocator, + resolveSymlink: o.resolveSymlink, + } +} + +// Hooks returns a hook to create the symlinks from the required CSV files +func (d symlinkHook) Hooks() ([]discover.Hook, error) { + return d.hookCreator.Create("create-symlinks", d.getCSVFileSymlinks()...).Hooks() +} + +// getSymlinkCandidates returns a list of symlinks that are candidates for being created. +func (d symlinkHook) getSymlinkCandidates() []string { + var candidates []string + for _, target := range d.targets { + reslovedSymlinkChain, err := d.symlinkChainLocator.Locate(target) + if err != nil { + d.logger.Warningf("Failed to locate symlink %v", target) + continue + } + candidates = append(candidates, reslovedSymlinkChain...) + } + return candidates +} + +func (d symlinkHook) getCSVFileSymlinks() []string { + var links []string + created := make(map[string]bool) + // candidates is a list of absolute paths to symlinks in a chain, or the final target of the chain. + for _, candidate := range d.getSymlinkCandidates() { + target, err := d.resolveSymlink(candidate) + if err != nil { + d.logger.Debugf("Skipping invalid link: %v", err) + continue + } else if target == candidate { + d.logger.Debugf("%v is not a symlink", candidate) + continue + } + + link := fmt.Sprintf("%v::%v", target, candidate) + if created[link] { + d.logger.Debugf("skipping duplicate link: %v", link) + continue + } + created[link] = true + + links = append(links, link) + } + + return links +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/tegra.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/tegra.go new file mode 100644 index 00000000..6ad774b4 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/tegra.go @@ -0,0 +1,162 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package tegra + +import ( + "fmt" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks" +) + +type tegraOptions struct { + logger logger.Interface + csvFiles []string + driverRoot string + devRoot string + hookCreator discover.HookCreator + ldconfigPath string + librarySearchPaths []string + ignorePatterns ignoreMountSpecPatterns + + // The following can be overridden for testing + symlinkLocator lookup.Locator + symlinkChainLocator lookup.Locator + // TODO: This should be replaced by a regular mock + resolveSymlink func(string) (string, error) +} + +// Option defines a functional option for configuring a Tegra discoverer. +type Option func(*tegraOptions) + +// New creates a new tegra discoverer using the supplied options. +func New(opts ...Option) (discover.Discover, error) { + o := &tegraOptions{} + for _, opt := range opts { + opt(o) + } + + if o.devRoot == "" { + o.devRoot = o.driverRoot + } + + if o.symlinkLocator == nil { + o.symlinkLocator = lookup.NewSymlinkLocator( + lookup.WithLogger(o.logger), + lookup.WithRoot(o.driverRoot), + lookup.WithSearchPaths(append(o.librarySearchPaths, "/")...), + ) + } + + if o.symlinkChainLocator == nil { + o.symlinkChainLocator = lookup.NewSymlinkChainLocator( + lookup.WithLogger(o.logger), + lookup.WithRoot(o.driverRoot), + ) + } + + if o.resolveSymlink == nil { + o.resolveSymlink = symlinks.Resolve + } + + csvDiscoverer, err := o.newDiscovererFromCSVFiles() + if err != nil { + return nil, fmt.Errorf("failed to create CSV discoverer: %v", err) + } + + ldcacheUpdateHook, err := discover.NewLDCacheUpdateHook(o.logger, csvDiscoverer, o.hookCreator, o.ldconfigPath) + if err != nil { + return nil, fmt.Errorf("failed to create ldcach update hook discoverer: %v", err) + } + + tegraSystemMounts := discover.NewMounts( + o.logger, + lookup.NewFileLocator(lookup.WithLogger(o.logger)), + "", + []string{ + "/etc/nv_tegra_release", + }, + ) + + d := discover.Merge( + csvDiscoverer, + // The ldcacheUpdateHook is added last to ensure that the created symlinks are included + ldcacheUpdateHook, + tegraSystemMounts, + ) + + return d, nil +} + +// WithLogger sets the logger for the discoverer. +func WithLogger(logger logger.Interface) Option { + return func(o *tegraOptions) { + o.logger = logger + } +} + +// WithDriverRoot sets the driver root for the discoverer. +func WithDriverRoot(driverRoot string) Option { + return func(o *tegraOptions) { + o.driverRoot = driverRoot + } +} + +// WithDevRoot sets the /dev root. +// If this is unset, the driver root is assumed. +func WithDevRoot(devRoot string) Option { + return func(o *tegraOptions) { + o.devRoot = devRoot + } +} + +// WithCSVFiles sets the CSV files for the discoverer. +func WithCSVFiles(csvFiles []string) Option { + return func(o *tegraOptions) { + o.csvFiles = csvFiles + } +} + +// WithHookCreator sets the hook creator for the discoverer. +func WithHookCreator(hookCreator discover.HookCreator) Option { + return func(o *tegraOptions) { + o.hookCreator = hookCreator + } +} + +// WithLdconfigPath sets the path to the ldconfig program +func WithLdconfigPath(ldconfigPath string) Option { + return func(o *tegraOptions) { + o.ldconfigPath = ldconfigPath + } +} + +// WithLibrarySearchPaths sets the library search paths for the discoverer. +func WithLibrarySearchPaths(librarySearchPaths ...string) Option { + return func(o *tegraOptions) { + o.librarySearchPaths = librarySearchPaths + } +} + +// WithIngorePatterns sets patterns to ignore in the CSV files +func WithIngorePatterns(ignorePatterns ...string) Option { + return func(o *tegraOptions) { + o.ignorePatterns = ignoreMountSpecPatterns(ignorePatterns) + } +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/api.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/api.go new file mode 100644 index 00000000..03135a0c --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/api.go @@ -0,0 +1,89 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec" +) + +// Interface defines the API for the nvcdi package +type Interface interface { + SpecGenerator + GetCommonEdits() (*cdi.ContainerEdits, error) + GetDeviceSpecsByID(...string) ([]specs.Device, error) + // Deprecated: GetAllDeviceSpecs is deprecated. Use GetDeviceSpecsByID("all") instead. + GetAllDeviceSpecs() ([]specs.Device, error) +} + +// A SpecGenerator is used to generate a complete CDI spec for a collected set +// of devices. +type SpecGenerator interface { + GetSpec(...string) (spec.Interface, error) +} + +// A DeviceSpecGenerator is used to generate the specs for one or more devices. +type DeviceSpecGenerator interface { + GetDeviceSpecs() ([]specs.Device, error) +} + +// A HookName represents one of the predefined NVIDIA CDI hooks. +type HookName = discover.HookName + +const ( + // AllHooks is a special hook name that allows all hooks to be matched. + AllHooks = discover.AllHooks + + // A CreateSymlinksHook is used to create symlinks in the container. + CreateSymlinksHook = discover.CreateSymlinksHook + // DisableDeviceNodeModificationHook refers to the hook used to ensure that + // device nodes are not created by libnvidia-ml.so or nvidia-smi in a + // container. + // Added in v1.17.8 + DisableDeviceNodeModificationHook = discover.DisableDeviceNodeModificationHook + // An EnableCudaCompatHook is used to enabled CUDA Forward Compatibility. + // Added in v1.17.5 + EnableCudaCompatHook = discover.EnableCudaCompatHook + // An UpdateLDCacheHook is used to update the ldcache in the container. + UpdateLDCacheHook = discover.UpdateLDCacheHook + + // Deprecated: Use CreateSymlinksHook instead. + HookCreateSymlinks = CreateSymlinksHook + // Deprecated: Use EnableCudaCompatHook instead. + HookEnableCudaCompat = EnableCudaCompatHook + // Deprecated: Use UpdateLDCacheHook instead. + HookUpdateLDCache = UpdateLDCacheHook +) + +// A FeatureFlag refers to a specific feature that can be toggled in the CDI api. +// All features are off by default. +type FeatureFlag string + +const ( + // FeatureEnableExplicitDriverLibraries enables the inclusion of a list of + // explicit driver libraries. + FeatureEnableExplicitDriverLibraries = FeatureFlag("enable-explicit-driver-libraries") + // FeatureDisableNvsandboxUtils disables the use of nvsandboxutils when + // querying devices. + FeatureDisableNvsandboxUtils = FeatureFlag("disable-nvsandbox-utils") + // FeatureEnableCoherentAnnotations enables the addition of annotations + // coherent or non-coherent devices. + FeatureEnableCoherentAnnotations = FeatureFlag("enable-coherent-annotations") +) diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/common-nvml.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/common-nvml.go new file mode 100644 index 00000000..fbb5f01d --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/common-nvml.go @@ -0,0 +1,56 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" +) + +// newCommonNVMLDiscoverer returns a discoverer for entities that are not associated with a specific CDI device. +// This includes driver libraries and meta devices, for example. +func (l *nvmllib) newCommonNVMLDiscoverer() (discover.Discover, error) { + metaDevices := discover.NewCharDeviceDiscoverer( + l.logger, + l.devRoot, + []string{ + "/dev/nvidia-modeset", + "/dev/nvidia-uvm-tools", + "/dev/nvidia-uvm", + "/dev/nvidiactl", + }, + ) + + graphicsMounts, err := discover.NewGraphicsMountsDiscoverer(l.logger, l.driver, l.hookCreator) + if err != nil { + l.logger.Warningf("failed to create discoverer for graphics mounts: %v", err) + } + + driverFiles, err := l.NewDriverDiscoverer() + if err != nil { + return nil, fmt.Errorf("failed to create discoverer for driver files: %v", err) + } + + d := discover.Merge( + metaDevices, + graphicsMounts, + driverFiles, + ) + + return d, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/device-wsl.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/device-wsl.go new file mode 100644 index 00000000..0f9e1ffd --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/device-wsl.go @@ -0,0 +1,37 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +const ( + dxgDeviceNode = "/dev/dxg" +) + +// newDXGDeviceDiscoverer returns a Discoverer for DXG devices under WSL2. +func newDXGDeviceDiscoverer(logger logger.Interface, devRoot string) discover.Discover { + deviceNodes := discover.NewCharDeviceDiscoverer( + logger, + devRoot, + []string{dxgDeviceNode}, + ) + + return deviceNodes +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/driver-nvml.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/driver-nvml.go new file mode 100644 index 00000000..e145a2d6 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/driver-nvml.go @@ -0,0 +1,290 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "golang.org/x/sys/unix" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root" +) + +// NewDriverDiscoverer creates a discoverer for the libraries and binaries associated with a driver installation. +// The supplied NVML Library is used to query the expected driver version. +func (l *nvmllib) NewDriverDiscoverer() (discover.Discover, error) { + return (*nvcdilib)(l).newDriverVersionDiscoverer() +} + +func (l *nvcdilib) newDriverVersionDiscoverer() (discover.Discover, error) { + version, err := l.driver.Version() + if err != nil || version == "" || version == "*.*" { + return nil, fmt.Errorf("failed to determine driver version (%q): %w", version, err) + } + + libcudasoParentDirPath, err := l.driver.GetLibcudaParentDir() + if err != nil { + return nil, fmt.Errorf("failed to get libcuda.so parent path: %w", err) + } + + libraries, err := l.NewDriverLibraryDiscoverer(version, libcudasoParentDirPath) + if err != nil { + return nil, fmt.Errorf("failed to create discoverer for driver libraries: %v", err) + } + + ipcs, err := discover.NewIPCDiscoverer(l.logger, l.driver.Root) + if err != nil { + return nil, fmt.Errorf("failed to create discoverer for IPC sockets: %v", err) + } + + firmwares, err := NewDriverFirmwareDiscoverer(l.logger, l.driver.Root, version) + if err != nil { + return nil, fmt.Errorf("failed to create discoverer for GSP firmware: %v", err) + } + + binaries := NewDriverBinariesDiscoverer(l.logger, l.driver.Root) + + d := discover.Merge( + libraries, + ipcs, + firmwares, + binaries, + ) + + return d, nil +} + +// NewDriverLibraryDiscoverer creates a discoverer for the libraries associated with the specified driver version. +func (l *nvcdilib) NewDriverLibraryDiscoverer(version string, libcudaSoParentDirPath string) (discover.Discover, error) { + versionSuffixLibraryMounts, err := l.getVersionSuffixDriverLibraryMounts(version) + if err != nil { + return nil, err + } + explicitLibraryMounts, err := l.getExplicitDriverLibraryMounts() + if err != nil { + return nil, err + } + + libraries := discover.Merge( + versionSuffixLibraryMounts, + explicitLibraryMounts, + ) + + var discoverers []discover.Discover + + driverDotSoSymlinksDiscoverer := discover.WithDriverDotSoSymlinks( + l.logger, + libraries, + // Since we don't only match version suffixes, we now need to match on wildcards. + "", + l.hookCreator, + ) + discoverers = append(discoverers, driverDotSoSymlinksDiscoverer) + + cudaCompatLibHookDiscoverer := discover.NewCUDACompatHookDiscoverer(l.logger, l.hookCreator, version) + discoverers = append(discoverers, cudaCompatLibHookDiscoverer) + + updateLDCache, _ := discover.NewLDCacheUpdateHook(l.logger, libraries, l.hookCreator, l.ldconfigPath) + discoverers = append(discoverers, updateLDCache) + + disableDeviceNodeModification := l.hookCreator.Create(DisableDeviceNodeModificationHook) + discoverers = append(discoverers, disableDeviceNodeModification) + + libCudaSoParentDirectoryPath, err := l.driver.GetLibcudaParentDir() + if err != nil { + return nil, fmt.Errorf("failed to get libcuda.so parent directory path: %w", err) + } + environmentVariable := &discover.EnvVar{ + Name: "NVIDIA_CTK_LIBCUDA_DIR", + Value: libCudaSoParentDirectoryPath, + } + discoverers = append(discoverers, environmentVariable) + + d := discover.Merge(discoverers...) + + return d, nil +} + +func (l *nvcdilib) getVersionSuffixDriverLibraryMounts(version string) (discover.Discover, error) { + versionSuffixLibraryPaths, err := getVersionLibs(l.logger, l.driver, version) + if err != nil { + return nil, fmt.Errorf("failed to get libraries for driver version: %v", err) + } + + mounts := discover.NewMounts( + l.logger, + lookup.NewFileLocator( + lookup.WithLogger(l.logger), + lookup.WithRoot(l.driver.Root), + ), + l.driver.Root, + versionSuffixLibraryPaths, + ) + + return mounts, nil +} + +func (l *nvcdilib) getExplicitDriverLibraryMounts() (discover.Discover, error) { + if !l.featureFlags[FeatureEnableExplicitDriverLibraries] { + return nil, nil + } + + // List of explicit libraries to locate + // TODO(ArangoGutierrez): we should load the version of the libraries from + // the sandboxutils-filelist or have a way to allow users to specify the + // libraries to mount from the config file. + explicitLibraries := []string{ + "libEGL.so", + "libGL.so", + "libGLESv1_CM.so", + "libGLESv2.so", + "libGLX.so", + "libGLdispatch.so", + "libOpenCL.so", + "libOpenGL.so", + "libnvidia-api.so", + "libnvidia-egl-xcb.so", + "libnvidia-egl-xlib.so", + } + + driverLibraryLocator, err := l.driver.DriverLibraryLocator() + if err != nil { + return nil, fmt.Errorf("failed to get driver library locator: %w", err) + } + mounts := discover.NewMounts( + l.logger, + driverLibraryLocator, + l.driver.Root, + explicitLibraries, + ) + + return mounts, nil + +} + +func getUTSRelease() (string, error) { + utsname := &unix.Utsname{} + if err := unix.Uname(utsname); err != nil { + return "", err + } + return unix.ByteSliceToString(utsname.Release[:]), nil +} + +func getFirmwareSearchPaths(logger logger.Interface) ([]string, error) { + + var firmwarePaths []string + if p := getCustomFirmwareClassPath(logger); p != "" { + logger.Debugf("using custom firmware class path: %s", p) + firmwarePaths = append(firmwarePaths, p) + } + + utsRelease, err := getUTSRelease() + if err != nil { + return nil, fmt.Errorf("failed to get UTS_RELEASE: %v", err) + } + + standardPaths := []string{ + filepath.Join("/lib/firmware/updates/", utsRelease), + "/lib/firmware/updates/", + filepath.Join("/lib/firmware/", utsRelease), + "/lib/firmware/", + } + + return append(firmwarePaths, standardPaths...), nil +} + +// getCustomFirmwareClassPath returns the custom firmware class path if it exists. +func getCustomFirmwareClassPath(logger logger.Interface) string { + customFirmwareClassPath, err := os.ReadFile("/sys/module/firmware_class/parameters/path") + if err != nil { + logger.Warningf("failed to get custom firmware class path: %v", err) + return "" + } + + return strings.TrimSpace(string(customFirmwareClassPath)) +} + +// NewDriverFirmwareDiscoverer creates a discoverer for GSP firmware associated with the specified driver version. +func NewDriverFirmwareDiscoverer(logger logger.Interface, driverRoot string, version string) (discover.Discover, error) { + gspFirmwareSearchPaths, err := getFirmwareSearchPaths(logger) + if err != nil { + return nil, fmt.Errorf("failed to get firmware search paths: %v", err) + } + gspFirmwarePaths := filepath.Join("nvidia", version, "gsp*.bin") + return discover.NewMounts( + logger, + lookup.NewFileLocator( + lookup.WithLogger(logger), + lookup.WithRoot(driverRoot), + lookup.WithSearchPaths(gspFirmwareSearchPaths...), + ), + driverRoot, + []string{gspFirmwarePaths}, + ), nil +} + +// NewDriverBinariesDiscoverer creates a discoverer for GSP firmware associated with the GPU driver. +func NewDriverBinariesDiscoverer(logger logger.Interface, driverRoot string) discover.Discover { + return discover.NewMounts( + logger, + lookup.NewExecutableLocator(logger, driverRoot), + driverRoot, + []string{ + "nvidia-smi", /* System management interface */ + "nvidia-debugdump", /* GPU coredump utility */ + "nvidia-persistenced", /* Persistence mode utility */ + "nvidia-cuda-mps-control", /* Multi process service CLI */ + "nvidia-cuda-mps-server", /* Multi process service server */ + "nvidia-imex", /* NVIDIA IMEX Daemon */ + "nvidia-imex-ctl", /* NVIDIA IMEX control */ + }, + ) +} + +// getVersionLibs checks the LDCache for libraries ending in the specified driver version. +// Although the ldcache at the specified driverRoot is queried, the paths are returned relative to this driverRoot. +// This allows the standard mount location logic to be used for resolving the mounts. +func getVersionLibs(logger logger.Interface, driver *root.Driver, version string) ([]string, error) { + logger.Infof("Using driver version %v", version) + + libraries, err := driver.DriverLibraryLocator("vdpau") + if err != nil { + return nil, fmt.Errorf("failed to get driver library locator: %w", err) + } + + libs, err := libraries.Locate("*.so." + version) + if err != nil { + return nil, fmt.Errorf("failed to locate libraries for driver version %v: %v", version, err) + } + + if driver.Root == "/" || driver.Root == "" { + return libs, nil + } + + var relative []string + for _, l := range libs { + relative = append(relative, strings.TrimPrefix(l, driver.Root)) + } + + return relative, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/driver-wsl.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/driver-wsl.go new file mode 100644 index 00000000..041c27ce --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/driver-wsl.go @@ -0,0 +1,127 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + "path/filepath" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" +) + +var requiredDriverStoreFiles = []string{ + "libcuda.so.1.1", /* Core library for cuda support */ + "libcuda_loader.so", /* Core library for cuda support on WSL */ + "libnvidia-ptxjitcompiler.so.1", /* Core library for PTX Jit support */ + "libnvidia-ml.so.1", /* Core library for nvml */ + "libnvidia-ml_loader.so", /* Core library for nvml on WSL */ + "libdxcore.so", /* Core library for dxcore support */ + "libnvdxgdmal.so.1", /* dxgdmal library for cuda */ + "nvcubins.bin", /* Binary containing GPU code for cuda */ + "nvidia-smi", /* nvidia-smi binary*/ +} + +// newWSLDriverDiscoverer returns a Discoverer for WSL2 drivers. +func newWSLDriverDiscoverer(logger logger.Interface, driverRoot string, hookCreator discover.HookCreator, ldconfigPath string) (discover.Discover, error) { + if err := dxcore.Init(); err != nil { + return nil, fmt.Errorf("failed to initialize dxcore: %w", err) + } + defer func() { + if err := dxcore.Shutdown(); err != nil { + logger.Warningf("failed to shutdown dxcore: %w", err) + } + }() + + driverStorePaths := dxcore.GetDriverStorePaths() + if len(driverStorePaths) == 0 { + return nil, fmt.Errorf("no driver store paths found") + } + if len(driverStorePaths) > 1 { + logger.Warningf("Found multiple driver store paths: %v", driverStorePaths) + } + logger.Infof("Using WSL driver store paths: %v", driverStorePaths) + + driverStorePaths = append(driverStorePaths, "/usr/lib/wsl/lib") + + driverStoreMounts := discover.NewMounts( + logger, + lookup.NewFileLocator( + lookup.WithLogger(logger), + lookup.WithSearchPaths( + driverStorePaths..., + ), + lookup.WithCount(1), + ), + driverRoot, + requiredDriverStoreFiles, + ) + + symlinkHook := nvidiaSMISimlinkHook{ + logger: logger, + mountsFrom: driverStoreMounts, + hookCreator: hookCreator, + } + + ldcacheHook, _ := discover.NewLDCacheUpdateHook(logger, driverStoreMounts, hookCreator, ldconfigPath) + + d := discover.Merge( + driverStoreMounts, + symlinkHook, + ldcacheHook, + ) + + return d, nil +} + +type nvidiaSMISimlinkHook struct { + discover.None + logger logger.Interface + mountsFrom discover.Discover + hookCreator discover.HookCreator +} + +// Hooks returns a hook that creates a symlink to nvidia-smi in the driver store. +// On WSL2 the driver store location is used unchanged, for this reason we need +// to create a symlink from /usr/bin/nvidia-smi to the nvidia-smi binary in the +// driver store. +func (m nvidiaSMISimlinkHook) Hooks() ([]discover.Hook, error) { + mounts, err := m.mountsFrom.Mounts() + if err != nil { + return nil, fmt.Errorf("failed to discover mounts: %w", err) + } + + var target string + for _, mount := range mounts { + if filepath.Base(mount.Path) == "nvidia-smi" { + target = mount.Path + break + } + } + + if target == "" { + m.logger.Warningf("Failed to find nvidia-smi in mounts: %v", mounts) + return nil, nil + } + link := "/usr/bin/nvidia-smi" + links := []string{fmt.Sprintf("%s::%s", target, link)} + symlinkHook := m.hookCreator.Create(CreateSymlinksHook, links...) + + return symlinkHook.Hooks() +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/full-gpu-nvml.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/full-gpu-nvml.go new file mode 100644 index 00000000..c52f44e4 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/full-gpu-nvml.go @@ -0,0 +1,186 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/device" + "github.com/NVIDIA/go-nvml/pkg/nvml" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/edits" + "github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu" +) + +// A fullGPUDeviceSpecGenerator generates the CDI device specifications for a +// single full GPU. +type fullGPUDeviceSpecGenerator struct { + *nvmllib + uuid string + index int + + featureFlags map[FeatureFlag]bool +} + +var _ DeviceSpecGenerator = (*fullGPUDeviceSpecGenerator)(nil) + +func (l *fullGPUDeviceSpecGenerator) GetUUID() (string, error) { + return l.uuid, nil +} + +func (l *nvmllib) newFullGPUDeviceSpecGeneratorFromDevice(index int, d device.Device, featureFlags map[FeatureFlag]bool) (*fullGPUDeviceSpecGenerator, error) { + uuid, ret := d.GetUUID() + if ret != nvml.SUCCESS { + return nil, fmt.Errorf("failed to get device UUID: %v", ret) + } + e := &fullGPUDeviceSpecGenerator{ + nvmllib: l, + uuid: uuid, + index: index, + + featureFlags: featureFlags, + } + + return e, nil +} + +func (l *nvmllib) newFullGPUDeviceSpecGeneratorFromNVMLDevice(uuid string, nvmlDevice nvml.Device, featureFlags map[FeatureFlag]bool) (DeviceSpecGenerator, error) { + index, ret := nvmlDevice.GetIndex() + if ret != nvml.SUCCESS { + return nil, fmt.Errorf("failed to get device index: %v", ret) + } + + e := &fullGPUDeviceSpecGenerator{ + nvmllib: l, + uuid: uuid, + index: index, + + featureFlags: featureFlags, + } + return e, nil +} + +func (l *fullGPUDeviceSpecGenerator) GetDeviceSpecs() ([]specs.Device, error) { + deviceEdits, err := l.getDeviceEdits() + if err != nil { + return nil, fmt.Errorf("failed to get CDI device edits: %w", err) + } + + names, err := l.getNames() + if err != nil { + return nil, fmt.Errorf("failed to get device names: %w", err) + } + + annotations, err := l.getDeviceAnnotations() + if err != nil { + l.logger.Warning("Ignoring error getting device annotations for device(s) %v: %v", names, err) + annotations = nil + } + var deviceSpecs []specs.Device + for _, name := range names { + deviceSpec := specs.Device{ + Name: name, + ContainerEdits: *deviceEdits.ContainerEdits, + Annotations: annotations, + } + deviceSpecs = append(deviceSpecs, deviceSpec) + } + + return deviceSpecs, nil +} + +func (l *fullGPUDeviceSpecGenerator) device() (device.Device, error) { + return l.devicelib.NewDeviceByUUID(l.uuid) +} + +func (l *fullGPUDeviceSpecGenerator) getDeviceAnnotations() (map[string]string, error) { + if !l.featureFlags[FeatureEnableCoherentAnnotations] { + return nil, nil + } + + device, err := l.device() + if err != nil { + return nil, err + } + + // TODO: Should we distinguish between not-supported and disabled? + isCoherent, err := device.IsCoherent() + if err != nil { + return nil, fmt.Errorf("failed to check device coherence: %w", err) + } + + annotations := map[string]string{ + "gpu.nvidia.com/coherent": fmt.Sprintf("%v", isCoherent), + } + + return annotations, nil +} + +// GetGPUDeviceEdits returns the CDI edits for the full GPU represented by 'device'. +func (l *fullGPUDeviceSpecGenerator) getDeviceEdits() (*cdi.ContainerEdits, error) { + device, err := l.device() + if err != nil { + return nil, err + } + + deviceDiscoverer, err := l.newFullGPUDiscoverer(device) + if err != nil { + return nil, fmt.Errorf("failed to create device discoverer: %v", err) + } + + editsForDevice, err := edits.FromDiscoverer(deviceDiscoverer) + if err != nil { + return nil, fmt.Errorf("failed to create container edits for device: %v", err) + } + + return editsForDevice, nil +} + +func (l *fullGPUDeviceSpecGenerator) getNames() ([]string, error) { + return l.deviceNamers.GetDeviceNames(l.index, l) +} + +// newFullGPUDiscoverer creates a discoverer for the full GPU defined by the specified device. +func (l *fullGPUDeviceSpecGenerator) newFullGPUDiscoverer(d device.Device) (discover.Discover, error) { + deviceNodes, err := dgpu.NewForDevice(d, + dgpu.WithDevRoot(l.devRoot), + dgpu.WithLogger(l.logger), + dgpu.WithHookCreator(l.hookCreator), + dgpu.WithNvsandboxuitilsLib(l.nvsandboxutilslib), + ) + if err != nil { + return nil, fmt.Errorf("failed to create device discoverer: %v", err) + } + + deviceFolderPermissionHooks := newDeviceFolderPermissionHookDiscoverer( + l.logger, + l.devRoot, + l.hookCreator, + deviceNodes, + ) + + dd := discover.Merge( + deviceNodes, + deviceFolderPermissionHooks, + ) + + return dd, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/gated.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/gated.go new file mode 100644 index 00000000..853e4d04 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/gated.go @@ -0,0 +1,74 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/edits" +) + +type gatedlib nvcdilib + +var _ deviceSpecGeneratorFactory = (*gatedlib)(nil) + +func (l *gatedlib) DeviceSpecGenerators(...string) (DeviceSpecGenerator, error) { + return l, nil +} + +// GetDeviceSpecs returns the CDI device specs for a single all device. +func (l *gatedlib) GetDeviceSpecs() ([]specs.Device, error) { + discoverer, err := l.getModeDiscoverer() + if err != nil { + return nil, fmt.Errorf("failed to create discoverer for mode %q: %w", l.mode, err) + } + edits, err := edits.FromDiscoverer(discoverer) + if err != nil { + return nil, fmt.Errorf("failed to create container edits: %w", err) + } + + deviceSpec := specs.Device{ + Name: "all", + ContainerEdits: *edits.ContainerEdits, + } + + return []specs.Device{deviceSpec}, nil +} + +func (l *gatedlib) getModeDiscoverer() (discover.Discover, error) { + switch l.mode { + case ModeGdrcopy: + return discover.NewGDRCopyDiscoverer(l.logger, l.devRoot) + case ModeGds: + return discover.NewGDSDiscoverer(l.logger, l.driverRoot, l.devRoot) + case ModeMofed: + return discover.NewMOFEDDiscoverer(l.logger, l.driverRoot) + case ModeNvswitch: + return discover.NewNvSwitchDiscoverer(l.logger, l.devRoot) + default: + return nil, fmt.Errorf("unrecognized mode") + } +} + +// GetCommonEdits generates a CDI specification that can be used for ANY devices +func (l *gatedlib) GetCommonEdits() (*cdi.ContainerEdits, error) { + return edits.FromDiscoverer(discover.None{}) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-csv.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-csv.go new file mode 100644 index 00000000..6380d79d --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-csv.go @@ -0,0 +1,86 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/edits" + "github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra" +) + +type csvlib nvcdilib + +var _ deviceSpecGeneratorFactory = (*csvlib)(nil) + +func (l *csvlib) DeviceSpecGenerators(ids ...string) (DeviceSpecGenerator, error) { + for _, id := range ids { + switch id { + case "all": + case "0": + default: + return nil, fmt.Errorf("unsupported device id: %v", id) + } + } + + return l, nil +} + +// GetDeviceSpecs returns the CDI device specs for a single device. +func (l *csvlib) GetDeviceSpecs() ([]specs.Device, error) { + d, err := tegra.New( + tegra.WithLogger(l.logger), + tegra.WithDriverRoot(l.driverRoot), + tegra.WithDevRoot(l.devRoot), + tegra.WithHookCreator(l.hookCreator), + tegra.WithLdconfigPath(l.ldconfigPath), + tegra.WithCSVFiles(l.csvFiles), + tegra.WithLibrarySearchPaths(l.librarySearchPaths...), + tegra.WithIngorePatterns(l.csvIgnorePatterns...), + ) + if err != nil { + return nil, fmt.Errorf("failed to create discoverer for CSV files: %v", err) + } + e, err := edits.FromDiscoverer(d) + if err != nil { + return nil, fmt.Errorf("failed to create container edits for CSV files: %v", err) + } + + names, err := l.deviceNamers.GetDeviceNames(0, uuidIgnored{}) + if err != nil { + return nil, fmt.Errorf("failed to get device name: %v", err) + } + var deviceSpecs []specs.Device + for _, name := range names { + deviceSpec := specs.Device{ + Name: name, + ContainerEdits: *e.ContainerEdits, + } + deviceSpecs = append(deviceSpecs, deviceSpec) + } + + return deviceSpecs, nil +} + +// GetCommonEdits generates a CDI specification that can be used for ANY devices +func (l *csvlib) GetCommonEdits() (*cdi.ContainerEdits, error) { + return edits.FromDiscoverer(discover.None{}) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-imex.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-imex.go new file mode 100644 index 00000000..2a178071 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-imex.go @@ -0,0 +1,123 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + "path/filepath" + "strconv" + "strings" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/edits" +) + +type imexlib nvcdilib + +type imexChannel struct { + id string + devRoot string +} + +var _ deviceSpecGeneratorFactory = (*imexlib)(nil) + +const ( + classImexChannel = "imex-channel" +) + +// GetCommonEdits returns an empty set of edits for IMEX devices. +func (l *imexlib) GetCommonEdits() (*cdi.ContainerEdits, error) { + return edits.FromDiscoverer(discover.None{}) +} + +// DeviceSpecGenerators returns the CDI device spec generators for the specified +// imex channel IDs. +// Valid IDs are: +// * numeric channel IDs +// * channel +// * the special ID 'all' +func (l *imexlib) DeviceSpecGenerators(ids ...string) (DeviceSpecGenerator, error) { + channelsIDs, err := l.getChannelIDs(ids...) + if err != nil { + return nil, err + } + + var deviceSpecGenerators DeviceSpecGenerators + for _, id := range channelsIDs { + deviceSpecGenerators = append(deviceSpecGenerators, &imexChannel{id: id, devRoot: l.devRoot}) + } + + return deviceSpecGenerators, nil +} + +func (l *imexlib) getChannelIDs(ids ...string) ([]string, error) { + var channelIDs []string + for _, id := range ids { + trimmed := strings.TrimPrefix(id, "channel") + if trimmed == "all" { + return l.getAllChannelIDs() + } + _, err := strconv.ParseUint(trimmed, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid channel ID %v: %w", id, err) + } + channelIDs = append(channelIDs, trimmed) + } + return channelIDs, nil +} + +// getAllChannelIDs returns the device IDs for all available IMEX channels. +func (l *imexlib) getAllChannelIDs() ([]string, error) { + channelsDiscoverer := discover.NewCharDeviceDiscoverer( + l.logger, + l.devRoot, + []string{"/dev/nvidia-caps-imex-channels/channel*"}, + ) + + channels, err := channelsDiscoverer.Devices() + if err != nil { + return nil, err + } + + var channelIDs []string + for _, channel := range channels { + channelID := filepath.Base(channel.Path) + channelIDs = append(channelIDs, strings.TrimPrefix(channelID, "channel")) + } + + return channelIDs, nil +} + +// GetDeviceSpecs returns the CDI device specs the specified IMEX channel. +func (l *imexChannel) GetDeviceSpecs() ([]specs.Device, error) { + path := "/dev/nvidia-caps-imex-channels/channel" + l.id + deviceSpec := specs.Device{ + Name: l.id, + ContainerEdits: specs.ContainerEdits{ + DeviceNodes: []*specs.DeviceNode{ + { + Path: path, + HostPath: filepath.Join(l.devRoot, path), + }, + }, + }, + } + return []specs.Device{deviceSpec}, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-nvml.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-nvml.go new file mode 100644 index 00000000..ee803168 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-nvml.go @@ -0,0 +1,259 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + "strconv" + "strings" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/device" + "github.com/NVIDIA/go-nvml/pkg/nvml" + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/edits" + "github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils" +) + +type nvmllib nvcdilib + +var _ deviceSpecGeneratorFactory = (*nvmllib)(nil) + +// GetCommonEdits generates a CDI specification that can be used for ANY devices +func (l *nvmllib) GetCommonEdits() (*cdi.ContainerEdits, error) { + common, err := l.newCommonNVMLDiscoverer() + if err != nil { + return nil, fmt.Errorf("failed to create discoverer for common entities: %v", err) + } + + return edits.FromDiscoverer(common) +} + +// DeviceSpecGenerators returns the CDI device spec generators for NVML devices +// with the specified IDs. +// Supported IDs are: +// * an index of a GPU or MIG device +// * a UUID of a GPU or MIG device +// * the special ID 'all' +func (l *nvmllib) DeviceSpecGenerators(ids ...string) (DeviceSpecGenerator, error) { + if err := l.init(); err != nil { + return nil, err + } + defer l.tryShutdown() + + dsgs, err := l.getDeviceSpecGeneratorsForIDs(ids...) + if err != nil { + return nil, err + } + return l.withInit(dsgs), nil +} + +func (l *nvmllib) getDeviceSpecGeneratorsForIDs(ids ...string) (DeviceSpecGenerator, error) { + var identifiers []device.Identifier + for _, id := range ids { + if id == "all" { + return l.getDeviceSpecGeneratorsForAllDevices() + } + identifiers = append(identifiers, device.Identifier(id)) + } + + uuids, err := l.normalizeDeviceIDs(identifiers...) + if err != nil { + return nil, err + } + + var DeviceSpecGenerators DeviceSpecGenerators + for _, uuid := range uuids { + device, ret := l.nvmllib.DeviceGetHandleByUUID(string(uuid)) + if ret != nvml.SUCCESS { + return nil, fmt.Errorf("failed to get device handle from UUID: %v", ret) + } + generator, err := l.newDeviceSpecGeneratorFromNVMLDevice(string(uuid), device) + if err != nil { + return nil, err + } + DeviceSpecGenerators = append(DeviceSpecGenerators, generator) + } + + return DeviceSpecGenerators, nil +} + +func (l *nvmllib) newDeviceSpecGeneratorFromNVMLDevice(id string, nvmlDevice nvml.Device) (DeviceSpecGenerator, error) { + isMig, ret := nvmlDevice.IsMigDeviceHandle() + if ret != nvml.SUCCESS { + return nil, fmt.Errorf("%v", ret) + } + if isMig { + return l.newMIGDeviceSpecGeneratorFromNVMLDevice(id, nvmlDevice) + } + + return l.newFullGPUDeviceSpecGeneratorFromNVMLDevice(id, nvmlDevice, l.featureFlags) +} + +// getDeviceSpecGeneratorsForAllDevices returns the CDI device spec generators +// for all NVML devices detected on the system. +// This includes full GPUs as well as MIG devices. +func (l *nvmllib) getDeviceSpecGeneratorsForAllDevices() (DeviceSpecGenerator, error) { + var DeviceSpecGenerators DeviceSpecGenerators + err := l.devicelib.VisitDevices(func(i int, d device.Device) error { + isMigEnabled, err := d.IsMigEnabled() + if err != nil { + return err + } + if isMigEnabled { + return nil + } + fullGPU, err := l.newFullGPUDeviceSpecGeneratorFromDevice(i, d, l.featureFlags) + if err != nil { + return err + } + DeviceSpecGenerators = append(DeviceSpecGenerators, fullGPU) + return nil + }) + if err != nil { + return nil, fmt.Errorf("failed to get full GPU device editors: %w", err) + } + + err = l.devicelib.VisitMigDevices(func(i int, d device.Device, j int, mig device.MigDevice) error { + migDevice, err := l.newMIGDeviceSpecGeneratorFromDevice(i, d, j, mig) + if err != nil { + return err + } + DeviceSpecGenerators = append(DeviceSpecGenerators, migDevice) + return nil + }) + if err != nil { + return nil, fmt.Errorf("failed to get MIG device editors: %w", err) + } + + return DeviceSpecGenerators, nil +} + +// TODO: move this to go-nvlib? +// normalizeDeviceID returns the UUIDs of the devices specified by the identifier. +func (l *nvmllib) normalizeDeviceIDs(identifiers ...device.Identifier) ([]device.Identifier, error) { + var uuids []device.Identifier + for _, id := range identifiers { + uuid, err := l.normalizeDeviceID(id) + if err != nil { + return nil, err + } + uuids = append(uuids, uuid) + } + return uuids, nil +} + +func (l *nvmllib) normalizeDeviceID(id device.Identifier) (device.Identifier, error) { + var err error + + if id.IsUUID() { + return id, nil + } + + if id.IsGpuIndex() { + idx, err := strconv.Atoi(string(id)) + if err != nil { + return "", fmt.Errorf("failed to convert device index to an int: %w", err) + } + dev, ret := l.nvmllib.DeviceGetHandleByIndex(idx) + if ret != nvml.SUCCESS { + return "", fmt.Errorf("failed to get device handle from index: %v", ret) + } + uuid, ret := dev.GetUUID() + if ret != nvml.SUCCESS { + return "", fmt.Errorf("failed to get device UUID: %v", ret) + } + return device.Identifier(uuid), nil + } + + if id.IsMigIndex() { + var gpuIdx, migIdx int + var parent nvml.Device + split := strings.SplitN(string(id), ":", 2) + if gpuIdx, err = strconv.Atoi(split[0]); err != nil { + return "", fmt.Errorf("failed to convert device index to an int: %w", err) + } + if migIdx, err = strconv.Atoi(split[1]); err != nil { + return "", fmt.Errorf("failed to convert device index to an int: %w", err) + } + parent, ret := l.nvmllib.DeviceGetHandleByIndex(gpuIdx) + if ret != nvml.SUCCESS { + return "", fmt.Errorf("failed to get parent device handle: %v", ret) + } + mig, ret := parent.GetMigDeviceHandleByIndex(migIdx) + if ret != nvml.SUCCESS { + return "", fmt.Errorf("failed to get MIG handle by index: %v", ret) + } + uuid, ret := mig.GetUUID() + if ret != nvml.SUCCESS { + return "", fmt.Errorf("failed to get MIG UUID: %v", ret) + } + return device.Identifier(uuid), nil + } + + return "", fmt.Errorf("identifier is not a valid UUID or index: %q", id) +} + +func (l *nvmllib) init() error { + if r := l.nvmllib.Init(); r != nvml.SUCCESS { + return fmt.Errorf("failed to initialize NVML: %w", r) + } + + if l.nvsandboxutilslib == nil { + return nil + } + if r := l.nvsandboxutilslib.Init(l.driverRoot); r != nvsandboxutils.SUCCESS { + l.logger.Warningf("Failed to init nvsandboxutils: %v; ignoring", r) + l.nvsandboxutilslib = nil + } + return nil +} + +func (l *nvmllib) tryShutdown() { + if l.nvsandboxutilslib != nil { + if r := l.nvsandboxutilslib.Shutdown(); r != nvsandboxutils.SUCCESS { + l.logger.Warningf("failed to shutdown nvsandboxutils: %v", r) + } + } + if r := l.nvmllib.Shutdown(); r != nvml.SUCCESS { + l.logger.Warningf("failed to shutdown NVML: %v", r) + } +} + +type deviceSpecGeneratorsWithAndShutdown struct { + *nvmllib + DeviceSpecGenerator +} + +func (l *nvmllib) withInit(dsg DeviceSpecGenerator) DeviceSpecGenerator { + return &deviceSpecGeneratorsWithAndShutdown{ + nvmllib: l, + DeviceSpecGenerator: dsg, + } +} + +// GetDeviceSpecs ensures that the init and shutdown are called before (and +// after) generating the required device specs. +func (d *deviceSpecGeneratorsWithAndShutdown) GetDeviceSpecs() ([]specs.Device, error) { + if err := d.init(); err != nil { + return nil, err + } + defer d.tryShutdown() + + return d.DeviceSpecGenerator.GetDeviceSpecs() +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-wsl.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-wsl.go new file mode 100644 index 00000000..76afbaa8 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib-wsl.go @@ -0,0 +1,60 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/edits" +) + +type wsllib nvcdilib + +var _ deviceSpecGeneratorFactory = (*wsllib)(nil) + +func (l *wsllib) DeviceSpecGenerators(...string) (DeviceSpecGenerator, error) { + return l, nil +} + +// GetDeviceSpecs returns the CDI device specs for a single all device. +func (l *wsllib) GetDeviceSpecs() ([]specs.Device, error) { + device := newDXGDeviceDiscoverer(l.logger, l.devRoot) + deviceEdits, err := edits.FromDiscoverer(device) + if err != nil { + return nil, fmt.Errorf("failed to create container edits for DXG device: %v", err) + } + + deviceSpec := specs.Device{ + Name: "all", + ContainerEdits: *deviceEdits.ContainerEdits, + } + + return []specs.Device{deviceSpec}, nil +} + +// GetCommonEdits generates a CDI specification that can be used for ANY devices +func (l *wsllib) GetCommonEdits() (*cdi.ContainerEdits, error) { + driver, err := newWSLDriverDiscoverer(l.logger, l.driverRoot, l.hookCreator, l.ldconfigPath) + if err != nil { + return nil, fmt.Errorf("failed to create discoverer for WSL driver: %v", err) + } + + return edits.FromDiscoverer(driver) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib.go new file mode 100644 index 00000000..4369a721 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/lib.go @@ -0,0 +1,284 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/device" + "github.com/NVIDIA/go-nvlib/pkg/nvlib/info" + "github.com/NVIDIA/go-nvml/pkg/nvml" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root" + "github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils" + "github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv" + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" +) + +type nvcdilib struct { + logger logger.Interface + nvmllib nvml.Interface + nvsandboxutilslib nvsandboxutils.Interface + mode Mode + devicelib device.Interface + deviceNamers DeviceNamers + driverRoot string + devRoot string + nvidiaCDIHookPath string + ldconfigPath string + configSearchPaths []string + librarySearchPaths []string + + csvFiles []string + csvIgnorePatterns []string + + vendor string + class string + + driver *root.Driver + infolib info.Interface + + mergedDeviceOptions []transform.MergedDeviceOption + + featureFlags map[FeatureFlag]bool + + disabledHooks []discover.HookName + enabledHooks []discover.HookName + hookCreator discover.HookCreator +} + +// New creates a new nvcdi library +func New(opts ...Option) (Interface, error) { + l := &nvcdilib{} + for _, opt := range opts { + opt(l) + } + if l.mode == "" { + l.mode = ModeAuto + } + if l.logger == nil { + l.logger = logger.New() + } + if len(l.deviceNamers) == 0 { + indexNamer, _ := NewDeviceNamer(DeviceNameStrategyIndex) + l.deviceNamers = []DeviceNamer{indexNamer} + } + if l.nvidiaCDIHookPath == "" { + l.nvidiaCDIHookPath = "/usr/bin/nvidia-cdi-hook" + } + if l.driverRoot == "" { + l.driverRoot = "/" + } + if l.devRoot == "" { + l.devRoot = l.driverRoot + } + + l.nvmllib = l.getNvmlLib() + l.nvsandboxutilslib = l.getNvsandboxUtilsLib() + l.driver = l.getDriver( + root.WithVersioner( + root.FirstOf( + nvsandboxutilslibWithVersion(l.nvsandboxutilslib), + nvmllibWithVersion(l.nvmllib), + ), + ), + ) + + if l.devicelib == nil { + l.devicelib = device.New(l.nvmllib) + } + if l.infolib == nil { + l.infolib = info.New( + info.WithRoot(l.driverRoot), + info.WithLogger(l.logger), + info.WithNvmlLib(l.nvmllib), + info.WithDeviceLib(l.devicelib), + ) + } + + var factory deviceSpecGeneratorFactory + switch l.resolveMode() { + case ModeCSV: + if len(l.csvFiles) == 0 { + l.csvFiles = csv.DefaultFileList() + } + factory = (*csvlib)(l) + case ModeManagement: + if l.vendor == "" { + l.vendor = "management.nvidia.com" + } + // Management containers in general do not require CUDA Forward compatibility. + l.disabledHooks = append(l.disabledHooks, HookEnableCudaCompat, DisableDeviceNodeModificationHook) + factory = (*managementlib)(l) + case ModeNvml: + factory = (*nvmllib)(l) + case ModeWsl: + factory = (*wsllib)(l) + case ModeGdrcopy, ModeGds, ModeMofed: + if l.class == "" { + l.class = string(l.mode) + } + factory = (*gatedlib)(l) + case ModeImex: + if l.class == "" { + l.class = classImexChannel + } + factory = (*imexlib)(l) + default: + return nil, fmt.Errorf("unknown mode %q", l.mode) + } + + // create hookCreator + l.hookCreator = discover.NewHookCreator( + discover.WithNVIDIACDIHookPath(l.nvidiaCDIHookPath), + discover.WithDisabledHooks(l.disabledHooks...), + discover.WithEnabledHooks(l.enabledHooks...), + ) + + w := wrapper{ + factory: factory, + vendor: l.vendor, + class: l.class, + mergedDeviceOptions: l.mergedDeviceOptions, + } + return &w, nil +} + +type nvmllibAsVersioner struct { + nvml.Interface +} + +func nvmllibWithVersion(nvmllib nvml.Interface) *nvmllibAsVersioner { + if nvmllib == nil { + return nil + } + return &nvmllibAsVersioner{ + Interface: nvmllib, + } +} + +func (l *nvmllibAsVersioner) Version() (string, error) { + if l == nil || l.Interface == nil { + return "", fmt.Errorf("nvml library not initialized") + } + + r := l.Init() + if r != nvml.SUCCESS { + return "", fmt.Errorf("failed to initialize nvml: %v", r) + } + defer func() { + _ = l.Shutdown() + }() + + version, r := l.SystemGetDriverVersion() + if r != nvml.SUCCESS { + return "", fmt.Errorf("failed to get driver version: %v", r) + } + return version, nil +} + +type nvsandboxutilslibAsVersioner struct { + nvsandboxutils.Interface +} + +func nvsandboxutilslibWithVersion(nvsandboxutilslib nvsandboxutils.Interface) *nvsandboxutilslibAsVersioner { + if nvsandboxutilslib == nil { + return nil + } + return &nvsandboxutilslibAsVersioner{ + Interface: nvsandboxutilslib, + } +} + +func (l *nvsandboxutilslibAsVersioner) Version() (string, error) { + if l == nil || l.Interface == nil { + return "", fmt.Errorf("libnvsandboxutils is not available") + } + + // Sandboxutils initialization should happen before this function is called + version, ret := l.GetDriverVersion() + if ret != nvsandboxutils.SUCCESS { + return "", fmt.Errorf("%v", ret) + } + return version, nil +} + +func (l *nvcdilib) getNvmlLib() nvml.Interface { + if l.nvmllib != nil { + return l.nvmllib + } + + var nvmlOpts []nvml.LibraryOption + candidates, err := l.getDriver().Libraries().Locate("libnvidia-ml.so.1") + if err != nil { + l.logger.Warningf("Ignoring error in locating libnvidia-ml.so.1: %v", err) + } else { + libNvidiaMlPath := candidates[0] + l.logger.Infof("Using %v", libNvidiaMlPath) + nvmlOpts = append(nvmlOpts, nvml.WithLibraryPath(libNvidiaMlPath)) + } + return nvml.New(nvmlOpts...) +} + +// getNvsandboxUtilsLib returns the nvsandboxutilslib to use for CDI spec +// generation. +func (l *nvcdilib) getNvsandboxUtilsLib() nvsandboxutils.Interface { + if l.featureFlags[FeatureDisableNvsandboxUtils] { + return nil + } + if l.nvsandboxutilslib != nil { + return l.nvsandboxutilslib + } + + var nvsandboxutilsOpts []nvsandboxutils.LibraryOption + // Set the library path for libnvidia-sandboxutils + candidates, err := l.getDriver().Libraries().Locate("libnvidia-sandboxutils.so.1") + if err != nil { + l.logger.Warningf("Ignoring error in locating libnvidia-sandboxutils.so.1: %v", err) + } else { + libNvidiaSandboxutilsPath := candidates[0] + l.logger.Infof("Using %v", libNvidiaSandboxutilsPath) + nvsandboxutilsOpts = append(nvsandboxutilsOpts, nvsandboxutils.WithLibraryPath(libNvidiaSandboxutilsPath)) + } + + // We try to initialize the library once to ensure that we have a valid installation. + lib := nvsandboxutils.New(nvsandboxutilsOpts...) + if r := lib.Init(l.driverRoot); r != nvsandboxutils.SUCCESS { + l.logger.Warningf("Failed to init nvsandboxutils: %v; ignoring", r) + return nil + } + defer func() { + _ = lib.Shutdown() + }() + + return lib +} + +func (l *nvcdilib) getDriver(additionalOptions ...root.Option) *root.Driver { + options := []root.Option{ + root.WithLogger(l.logger), + root.WithDriverRoot(l.driverRoot), + root.WithLibrarySearchPaths(l.librarySearchPaths...), + root.WithConfigSearchPaths(l.configSearchPaths...), + } + + options = append(options, additionalOptions...) + + return root.New(options...) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/management.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/management.go new file mode 100644 index 00000000..2c2c9fbe --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/management.go @@ -0,0 +1,153 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + "path/filepath" + "strings" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/edits" + "github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils" +) + +type managementlib nvcdilib + +var _ deviceSpecGeneratorFactory = (*managementlib)(nil) + +func (l *managementlib) DeviceSpecGenerators(...string) (DeviceSpecGenerator, error) { + return l, nil +} + +// GetDeviceSpecs returns the CDI device specs for a single all device. +func (m *managementlib) GetDeviceSpecs() ([]specs.Device, error) { + devices, err := m.newManagementDeviceDiscoverer() + if err != nil { + return nil, fmt.Errorf("failed to create device discoverer: %v", err) + } + + edits, err := edits.FromDiscoverer(devices) + if err != nil { + return nil, fmt.Errorf("failed to create edits from discoverer: %v", err) + } + + if len(edits.DeviceNodes) == 0 { + return nil, fmt.Errorf("no NVIDIA device nodes found") + } + + device := specs.Device{ + Name: "all", + ContainerEdits: *edits.ContainerEdits, + } + return []specs.Device{device}, nil +} + +// GetCommonEdits returns the common edits for use in managementlib containers. +func (m *managementlib) GetCommonEdits() (*cdi.ContainerEdits, error) { + if m.nvsandboxutilslib != nil { + if r := m.nvsandboxutilslib.Init(m.driverRoot); r != nvsandboxutils.SUCCESS { + m.logger.Warningf("Failed to init nvsandboxutils: %v; ignoring", r) + m.nvsandboxutilslib = nil + } + defer func() { + if m.nvsandboxutilslib == nil { + return + } + _ = m.nvsandboxutilslib.Shutdown() + }() + } + + driver, err := (*nvcdilib)(m).newDriverVersionDiscoverer() + if err != nil { + return nil, fmt.Errorf("failed to create driver library discoverer: %v", err) + } + + edits, err := edits.FromDiscoverer(driver) + if err != nil { + return nil, fmt.Errorf("failed to create edits from discoverer: %v", err) + } + + return edits, nil +} + +type managementDiscoverer struct { + discover.Discover +} + +// newManagementDeviceDiscoverer returns a discover.Discover that discovers device nodes for use in managementlib containers. +// NVML is not used to query devices and all device nodes are returned. +func (m *managementlib) newManagementDeviceDiscoverer() (discover.Discover, error) { + deviceNodes := discover.NewCharDeviceDiscoverer( + m.logger, + m.devRoot, + []string{ + "/dev/nvidia*", + "/dev/nvidia-caps/nvidia-cap*", + "/dev/nvidia-modeset", + "/dev/nvidia-uvm-tools", + "/dev/nvidia-uvm", + "/dev/nvidiactl", + "/dev/nvidia-caps-imex-channels/channel*", + }, + ) + + deviceFolderPermissionHooks := newDeviceFolderPermissionHookDiscoverer( + m.logger, + m.devRoot, + m.hookCreator, + deviceNodes, + ) + + d := discover.Merge( + &managementDiscoverer{deviceNodes}, + deviceFolderPermissionHooks, + ) + return d, nil +} + +func (m *managementDiscoverer) Devices() ([]discover.Device, error) { + devices, err := m.Discover.Devices() + if err != nil { + return devices, err + } + + var filteredDevices []discover.Device + for _, device := range devices { + if m.nodeIsBlocked(device.HostPath) { + continue + } + filteredDevices = append(filteredDevices, device) + } + + return filteredDevices, nil +} + +// nodeIsBlocked returns true if the specified device node should be ignored. +func (m managementDiscoverer) nodeIsBlocked(path string) bool { + blockedPrefixes := []string{"nvidia-fs", "nvidia-nvswitch", "nvidia-nvlink"} + nodeName := filepath.Base(path) + for _, prefix := range blockedPrefixes { + if strings.HasPrefix(nodeName, prefix) { + return true + } + } + return false +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/mig-device-nvml.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/mig-device-nvml.go new file mode 100644 index 00000000..2184e80b --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/mig-device-nvml.go @@ -0,0 +1,147 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/device" + "github.com/NVIDIA/go-nvml/pkg/nvml" + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/edits" + "github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu" +) + +type migDeviceSpecGenerator struct { + *fullGPUDeviceSpecGenerator + migIndex int + migUUID string +} + +var _ DeviceSpecGenerator = (*migDeviceSpecGenerator)(nil) + +func (l *migDeviceSpecGenerator) GetUUID() (string, error) { + return l.migUUID, nil +} + +func (l *nvmllib) newMIGDeviceSpecGeneratorFromDevice(i int, d device.Device, j int, m device.MigDevice) (*migDeviceSpecGenerator, error) { + parent, err := l.newFullGPUDeviceSpecGeneratorFromDevice(i, d, make(map[FeatureFlag]bool)) + if err != nil { + return nil, err + } + + migUUID, ret := m.GetUUID() + if ret != nvml.SUCCESS { + return nil, fmt.Errorf("failed to get MIG UUID: %v", ret) + } + + e := &migDeviceSpecGenerator{ + fullGPUDeviceSpecGenerator: parent, + migIndex: j, + migUUID: migUUID, + } + + return e, nil +} + +func (l *nvmllib) newMIGDeviceSpecGeneratorFromNVMLDevice(uuid string, nvmlMIGDevice nvml.Device) (DeviceSpecGenerator, error) { + migDevice, err := l.devicelib.NewMigDevice(nvmlMIGDevice) + if err != nil { + return nil, err + } + + nvmlParentDevice, ret := migDevice.GetDeviceHandleFromMigDeviceHandle() + if ret != nvml.SUCCESS { + return nil, fmt.Errorf("failed to get parent device handle: %v", ret) + } + parentDevice, err := l.devicelib.NewDevice(nvmlParentDevice) + if err != nil { + return nil, err + } + parentIndex, ret := parentDevice.GetIndex() + if ret != nvml.SUCCESS { + return nil, fmt.Errorf("failed to get parent device index: %v", ret) + } + + migDeviceIndex, ret := nvmlMIGDevice.GetIndex() + if ret != nvml.SUCCESS { + return nil, fmt.Errorf("failed to get MIG device index: %w", ret) + } + + return l.newMIGDeviceSpecGeneratorFromDevice(parentIndex, parentDevice, migDeviceIndex, migDevice) +} + +func (l *migDeviceSpecGenerator) GetDeviceSpecs() ([]specs.Device, error) { + deviceEdits, err := l.getDeviceEdits() + if err != nil { + return nil, fmt.Errorf("failed to get CDI device edits: %w", err) + } + + names, err := l.getNames() + if err != nil { + return nil, fmt.Errorf("failed to get device names: %w", err) + } + + var deviceSpecs []specs.Device + for _, name := range names { + deviceSpec := specs.Device{ + Name: name, + ContainerEdits: *deviceEdits.ContainerEdits, + } + deviceSpecs = append(deviceSpecs, deviceSpec) + } + + return deviceSpecs, nil +} + +func (l *migDeviceSpecGenerator) migDevice() (device.MigDevice, error) { + return l.devicelib.NewMigDeviceByUUID(l.migUUID) +} + +// GetMIGDeviceEdits returns the CDI edits for the MIG device represented by 'mig' on 'parent'. +func (l *migDeviceSpecGenerator) getDeviceEdits() (*cdi.ContainerEdits, error) { + device, err := l.device() + if err != nil { + return nil, err + } + migDevice, err := l.migDevice() + if err != nil { + return nil, err + } + deviceNodes, err := dgpu.NewForMigDevice(device, migDevice, + dgpu.WithDevRoot(l.devRoot), + dgpu.WithLogger(l.logger), + dgpu.WithHookCreator(l.hookCreator), + dgpu.WithNvsandboxuitilsLib(l.nvsandboxutilslib), + ) + if err != nil { + return nil, fmt.Errorf("failed to create device discoverer: %v", err) + } + + editsForDevice, err := edits.FromDiscoverer(deviceNodes) + if err != nil { + return nil, fmt.Errorf("failed to create container edits for Compute Instance: %v", err) + } + + return editsForDevice, nil +} + +func (l *migDeviceSpecGenerator) getNames() ([]string, error) { + return l.deviceNamers.GetMigDeviceNames(l.index, l.fullGPUDeviceSpecGenerator, l.migIndex, l) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/mode.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/mode.go new file mode 100644 index 00000000..a68170ec --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/mode.go @@ -0,0 +1,127 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "sync" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/info" +) + +type Mode string + +const ( + // ModeAuto configures the CDI spec generator to automatically detect the system configuration + ModeAuto = Mode("auto") + // ModeNvml configures the CDI spec generator to use the NVML library. + ModeNvml = Mode("nvml") + // ModeWsl configures the CDI spec generator to generate a WSL spec. + ModeWsl = Mode("wsl") + // ModeManagement configures the CDI spec generator to generate a management spec. + ModeManagement = Mode("management") + // ModeGdrcopy configures the CDI spec generator to generate a GDR Copy spec. + ModeGdrcopy = Mode("gdrcopy") + // ModeGds configures the CDI spec generator to generate a GDS spec. + ModeGds = Mode("gds") + // ModeMofed configures the CDI spec generator to generate a MOFED spec. + ModeMofed = Mode("mofed") + // ModeCSV configures the CDI spec generator to generate a spec based on the contents of CSV + // mountspec files. + ModeCSV = Mode("csv") + // ModeImex configures the CDI spec generator to generate a spec for the available IMEX channels. + ModeImex = Mode("imex") + // ModeNvswitch configures the CDI spec generator to generate a spec for the available nvswitch devices. + ModeNvswitch = Mode("nvswitch") +) + +type modeConstraint interface { + string | Mode +} + +type modes struct { + lookup map[Mode]bool + all []Mode +} + +var validModes modes +var validModesOnce sync.Once + +func getModes() modes { + validModesOnce.Do(func() { + all := []Mode{ + ModeAuto, + ModeCSV, + ModeGdrcopy, + ModeGds, + ModeImex, + ModeManagement, + ModeMofed, + ModeNvml, + ModeNvswitch, + ModeWsl, + } + lookup := make(map[Mode]bool) + + for _, m := range all { + lookup[m] = true + } + + validModes = modes{ + lookup: lookup, + all: all, + } + }, + ) + return validModes +} + +// AllModes returns the set of valid modes. +func AllModes[T modeConstraint]() []T { + var output []T + for _, m := range getModes().all { + output = append(output, T(m)) + } + return output +} + +// IsValidMode checks whether a specified mode is valid. +func IsValidMode[T modeConstraint](mode T) bool { + return getModes().lookup[Mode(mode)] +} + +// resolveMode resolves the mode for CDI spec generation based on the current system. +func (l *nvcdilib) resolveMode() (rmode Mode) { + if l.mode != ModeAuto { + return l.mode + } + defer func() { + l.logger.Infof("Auto-detected mode as '%v'", rmode) + l.mode = rmode + }() + + platform := l.infolib.ResolvePlatform() + switch platform { + case info.PlatformNVML: + return ModeNvml + case info.PlatformTegra: + return ModeCSV + case info.PlatformWSL: + return ModeWsl + } + l.logger.Warningf("Unsupported platform detected: %v; assuming %v", platform, ModeNvml) + return ModeNvml +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/namer.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/namer.go new file mode 100644 index 00000000..8019f699 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/namer.go @@ -0,0 +1,167 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "errors" + "fmt" + + "github.com/NVIDIA/go-nvml/pkg/nvml" +) + +// UUIDer is an interface for getting UUIDs. +type UUIDer interface { + GetUUID() (string, error) +} + +// DeviceNamers represents a list of device namers +type DeviceNamers []DeviceNamer + +// DeviceNamer is an interface for getting device names +type DeviceNamer interface { + GetDeviceName(int, UUIDer) (string, error) + GetMigDeviceName(int, UUIDer, int, UUIDer) (string, error) +} + +// Supported device naming strategies +const ( + // DeviceNameStrategyIndex generates devices names such as 0 or 1:0 + DeviceNameStrategyIndex = "index" + // DeviceNameStrategyTypeIndex generates devices names such as gpu0 or mig1:0 + DeviceNameStrategyTypeIndex = "type-index" + // DeviceNameStrategyUUID uses the device UUID as the name + DeviceNameStrategyUUID = "uuid" +) + +type deviceNameIndex struct { + gpuPrefix string + migPrefix string +} +type deviceNameUUID struct{} + +// NewDeviceNamer creates a Device Namer based on the supplied strategy. +// This namer can be used to construct the names for MIG and GPU devices when generating the CDI spec. +func NewDeviceNamer(strategy string) (DeviceNamer, error) { + switch strategy { + case DeviceNameStrategyIndex: + return deviceNameIndex{}, nil + case DeviceNameStrategyTypeIndex: + return deviceNameIndex{gpuPrefix: "gpu", migPrefix: "mig"}, nil + case DeviceNameStrategyUUID: + return deviceNameUUID{}, nil + } + + return nil, fmt.Errorf("invalid device name strategy: %v", strategy) +} + +// GetDeviceName returns the name for the specified device based on the naming strategy +func (s deviceNameIndex) GetDeviceName(i int, _ UUIDer) (string, error) { + return fmt.Sprintf("%s%d", s.gpuPrefix, i), nil +} + +// GetMigDeviceName returns the name for the specified device based on the naming strategy +func (s deviceNameIndex) GetMigDeviceName(i int, _ UUIDer, j int, _ UUIDer) (string, error) { + return fmt.Sprintf("%s%d:%d", s.migPrefix, i, j), nil +} + +// GetDeviceName returns the name for the specified device based on the naming strategy +func (s deviceNameUUID) GetDeviceName(i int, d UUIDer) (string, error) { + uuid, err := d.GetUUID() + if err != nil { + return "", fmt.Errorf("failed to get device UUID: %v", err) + } + return uuid, nil +} + +// GetMigDeviceName returns the name for the specified device based on the naming strategy +func (s deviceNameUUID) GetMigDeviceName(i int, _ UUIDer, j int, mig UUIDer) (string, error) { + uuid, err := mig.GetUUID() + if err != nil { + return "", fmt.Errorf("failed to get device UUID: %v", err) + } + return uuid, nil +} + +//go:generate moq -rm -fmt=goimports -stub -out namer_nvml_mock.go . nvmlUUIDer +type nvmlUUIDer interface { + GetUUID() (string, nvml.Return) +} + +type convert struct { + nvmlUUIDer +} + +type uuidIgnored struct{} + +func (m uuidIgnored) GetUUID() (string, error) { + return "", nil +} + +type uuidUnsupported struct{} + +func (m convert) GetUUID() (string, error) { + if m.nvmlUUIDer == nil { + return uuidUnsupported{}.GetUUID() + } + uuid, ret := m.nvmlUUIDer.GetUUID() + if ret != nvml.SUCCESS { + return "", ret + } + return uuid, nil +} + +var errUUIDUnsupported = errors.New("GetUUID is not supported") + +func (m uuidUnsupported) GetUUID() (string, error) { + return "", errUUIDUnsupported +} + +func (l DeviceNamers) GetDeviceNames(i int, d UUIDer) ([]string, error) { + var names []string + for _, namer := range l { + name, err := namer.GetDeviceName(i, d) + if err != nil { + return nil, err + } + if name == "" { + continue + } + names = append(names, name) + } + if len(names) == 0 { + return nil, errors.New("no names defined") + } + return names, nil +} + +func (l DeviceNamers) GetMigDeviceNames(i int, d UUIDer, j int, mig UUIDer) ([]string, error) { + var names []string + for _, namer := range l { + name, err := namer.GetMigDeviceName(i, d, j, mig) + if err != nil { + return nil, err + } + if name == "" { + continue + } + names = append(names, name) + } + if len(names) == 0 { + return nil, errors.New("no names defined") + } + return names, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/namer_nvml_mock.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/namer_nvml_mock.go new file mode 100644 index 00000000..6a704b45 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/namer_nvml_mock.go @@ -0,0 +1,73 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package nvcdi + +import ( + "sync" + + "github.com/NVIDIA/go-nvml/pkg/nvml" +) + +// Ensure, that nvmlUUIDerMock does implement nvmlUUIDer. +// If this is not the case, regenerate this file with moq. +var _ nvmlUUIDer = &nvmlUUIDerMock{} + +// nvmlUUIDerMock is a mock implementation of nvmlUUIDer. +// +// func TestSomethingThatUsesnvmlUUIDer(t *testing.T) { +// +// // make and configure a mocked nvmlUUIDer +// mockednvmlUUIDer := &nvmlUUIDerMock{ +// GetUUIDFunc: func() (string, nvml.Return) { +// panic("mock out the GetUUID method") +// }, +// } +// +// // use mockednvmlUUIDer in code that requires nvmlUUIDer +// // and then make assertions. +// +// } +type nvmlUUIDerMock struct { + // GetUUIDFunc mocks the GetUUID method. + GetUUIDFunc func() (string, nvml.Return) + + // calls tracks calls to the methods. + calls struct { + // GetUUID holds details about calls to the GetUUID method. + GetUUID []struct { + } + } + lockGetUUID sync.RWMutex +} + +// GetUUID calls GetUUIDFunc. +func (mock *nvmlUUIDerMock) GetUUID() (string, nvml.Return) { + callInfo := struct { + }{} + mock.lockGetUUID.Lock() + mock.calls.GetUUID = append(mock.calls.GetUUID, callInfo) + mock.lockGetUUID.Unlock() + if mock.GetUUIDFunc == nil { + var ( + sOut string + returnOut nvml.Return + ) + return sOut, returnOut + } + return mock.GetUUIDFunc() +} + +// GetUUIDCalls gets all the calls that were made to GetUUID. +// Check the length with: +// +// len(mockednvmlUUIDer.GetUUIDCalls()) +func (mock *nvmlUUIDerMock) GetUUIDCalls() []struct { +} { + var calls []struct { + } + mock.lockGetUUID.RLock() + calls = mock.calls.GetUUID + mock.lockGetUUID.RUnlock() + return calls +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/options.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/options.go new file mode 100644 index 00000000..550b18ba --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/options.go @@ -0,0 +1,205 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "github.com/NVIDIA/go-nvlib/pkg/nvlib/device" + "github.com/NVIDIA/go-nvlib/pkg/nvlib/info" + "github.com/NVIDIA/go-nvml/pkg/nvml" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" +) + +// Option is a function that configures the nvcdilib +type Option func(*nvcdilib) + +// WithDeviceLib sets the device library for the library +func WithDeviceLib(devicelib device.Interface) Option { + return func(l *nvcdilib) { + l.devicelib = devicelib + } +} + +// WithInfoLib sets the info library for CDI spec generation. +func WithInfoLib(infolib info.Interface) Option { + return func(l *nvcdilib) { + l.infolib = infolib + } +} + +// WithDeviceNamers sets the device namer for the library +func WithDeviceNamers(namers ...DeviceNamer) Option { + return func(l *nvcdilib) { + l.deviceNamers = namers + } +} + +// WithDriverRoot sets the driver root for the library +func WithDriverRoot(root string) Option { + return func(l *nvcdilib) { + l.driverRoot = root + } +} + +// WithDevRoot sets the root where /dev is located. +func WithDevRoot(root string) Option { + return func(l *nvcdilib) { + l.devRoot = root + } +} + +// WithLogger sets the logger for the library +func WithLogger(logger logger.Interface) Option { + return func(l *nvcdilib) { + l.logger = logger + } +} + +// WithNVIDIACTKPath sets the path to the NVIDIA Container Toolkit CLI path for the library +// +// Deprecated: Use WithNVIDIACDIHookPath instead. +func WithNVIDIACTKPath(path string) Option { + return WithNVIDIACDIHookPath(path) +} + +// WithNVIDIACDIHookPath sets the path to the NVIDIA Container Toolkit CLI path for the library +func WithNVIDIACDIHookPath(path string) Option { + return func(l *nvcdilib) { + l.nvidiaCDIHookPath = path + } +} + +// WithLdconfigPath sets the path to the ldconfig program +func WithLdconfigPath(path string) Option { + return func(l *nvcdilib) { + l.ldconfigPath = path + } +} + +// WithNvmlLib sets the nvml library for the library +func WithNvmlLib(nvmllib nvml.Interface) Option { + return func(l *nvcdilib) { + l.nvmllib = nvmllib + } +} + +// WithMode sets the discovery mode for the library +func WithMode[m modeConstraint](mode m) Option { + return func(l *nvcdilib) { + l.mode = Mode(mode) + } +} + +// WithVendor sets the vendor for the library +func WithVendor(vendor string) Option { + return func(o *nvcdilib) { + o.vendor = vendor + } +} + +// WithClass sets the class for the library +func WithClass(class string) Option { + return func(o *nvcdilib) { + o.class = class + } +} + +// WithMergedDeviceOptions sets the merged device options for the library +// If these are not set, no merged device will be generated. +func WithMergedDeviceOptions(opts ...transform.MergedDeviceOption) Option { + return func(o *nvcdilib) { + o.mergedDeviceOptions = opts + } +} + +// WithCSVFiles sets the CSV files for the library +func WithCSVFiles(csvFiles []string) Option { + return func(o *nvcdilib) { + o.csvFiles = csvFiles + } +} + +// WithCSVIgnorePatterns sets the ignore patterns for entries in the CSV files. +func WithCSVIgnorePatterns(csvIgnorePatterns []string) Option { + return func(o *nvcdilib) { + o.csvIgnorePatterns = csvIgnorePatterns + } +} + +// WithConfigSearchPaths sets the search paths for config files. +func WithConfigSearchPaths(paths []string) Option { + return func(o *nvcdilib) { + o.configSearchPaths = paths + } +} + +// WithLibrarySearchPaths sets the library search paths. +// This is currently only used for CSV-mode. +func WithLibrarySearchPaths(paths []string) Option { + return func(o *nvcdilib) { + o.librarySearchPaths = paths + } +} + +// WithDisabledHooks allows specific hooks to be disabled. +func WithDisabledHooks[T string | HookName](hooks ...T) Option { + return func(o *nvcdilib) { + for _, hook := range hooks { + o.disabledHooks = append(o.disabledHooks, discover.HookName(hook)) + } + } +} + +// WithEnabledHooks explicitly enables a specific set of hooks. +// If a hook is explicitly enabled, this takes precedence over it being disabled. +func WithEnabledHooks[T string | HookName](hooks ...T) Option { + return func(o *nvcdilib) { + for _, hook := range hooks { + o.enabledHooks = append(o.enabledHooks, discover.HookName(hook)) + } + } +} + +// WithFeatureFlags allows the specified set of features to be toggled on. +func WithFeatureFlags[T string | FeatureFlag](featureFlags ...T) Option { + return func(o *nvcdilib) { + if o.featureFlags == nil { + o.featureFlags = make(map[FeatureFlag]bool) + } + for _, featureFlag := range featureFlags { + o.featureFlags[FeatureFlag(featureFlag)] = true + } + } +} + +// WithDisabledHook allows specific hooks to be disabled. +// This option can be specified multiple times for each hook. +// +// Deprecated: Use WithDisabledHooks instead +func WithDisabledHook[T string | HookName](hook T) Option { + return WithDisabledHooks(hook) +} + +// WithFeatureFlag allows specified features to be toggled on. +// This option can be specified multiple times for each feature flag. +// +// Deprecated: Use WithFeatureFlags +func WithFeatureFlag[T string | FeatureFlag](featureFlag T) Option { + return WithFeatureFlags(featureFlag) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/api.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/api.go new file mode 100644 index 00000000..918f56f2 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/api.go @@ -0,0 +1,42 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package spec + +import ( + "io" + + "tags.cncf.io/container-device-interface/specs-go" +) + +const ( + // DetectMinimumVersion is a constant that triggers a spec to detect the minimum required version. + // + // Deprecated: DetectMinimumVersion is deprecated and will be removed. + DetectMinimumVersion = "DETECT_MINIMUM_VERSION" + + // FormatJSON indicates a JSON output format + FormatJSON = "json" + // FormatYAML indicates a YAML output format + FormatYAML = "yaml" +) + +// Interface is the interface for the spec API +type Interface interface { + io.WriterTo + Save(string) error + Raw() *specs.Spec +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/builder.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/builder.go new file mode 100644 index 00000000..337a1dd1 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/builder.go @@ -0,0 +1,196 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package spec + +import ( + "fmt" + "os" + + "tags.cncf.io/container-device-interface/pkg/parser" + cdi "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" +) + +type builder struct { + raw *cdi.Spec + version string + vendor string + class string + deviceSpecs []cdi.Device + edits cdi.ContainerEdits + format string + + mergedDeviceOptions []transform.MergedDeviceOption + noSimplify bool + permissions os.FileMode + + transformOnSave transform.Transformer +} + +// newBuilder creates a new spec builder with the supplied options +func newBuilder(opts ...Option) *builder { + s := &builder{} + for _, opt := range opts { + opt(s) + } + + if s.raw != nil { + s.noSimplify = true + vendor, class := parser.ParseQualifier(s.raw.Kind) + if s.vendor == "" { + s.vendor = vendor + } + if s.class == "" { + s.class = class + } + if s.version == "" || s.version == DetectMinimumVersion { + s.version = s.raw.Version + } + } + if s.version == "" || s.version == DetectMinimumVersion { + s.transformOnSave = &setMinimumRequiredVersion{} + s.version = cdi.CurrentVersion + } + if s.vendor == "" { + s.vendor = "nvidia.com" + } + if s.class == "" { + s.class = "gpu" + } + if s.format == "" { + s.format = FormatYAML + } + if s.permissions == 0 { + s.permissions = 0644 + } + return s +} + +// Build builds a CDI spec form the spec builder. +func (o *builder) Build() (*spec, error) { + raw := o.raw + if raw == nil { + raw = &cdi.Spec{ + Version: o.version, + Kind: fmt.Sprintf("%s/%s", o.vendor, o.class), + Devices: o.deviceSpecs, + ContainerEdits: o.edits, + } + } + if raw.Version == "" { + raw.Version = o.version + } + + if !o.noSimplify { + err := transform.NewSimplifier().Transform(raw) + if err != nil { + return nil, fmt.Errorf("failed to simplify spec: %v", err) + } + } + + if len(o.mergedDeviceOptions) > 0 { + merge, err := transform.NewMergedDevice(o.mergedDeviceOptions...) + if err != nil { + return nil, fmt.Errorf("failed to create merged device transformer: %v", err) + } + if err := merge.Transform(raw); err != nil { + return nil, fmt.Errorf("failed to merge devices: %v", err) + } + } + + s := spec{ + Spec: raw, + format: o.format, + permissions: o.permissions, + transformOnSave: o.transformOnSave, + } + return &s, nil +} + +// Option defines a function that can be used to configure the spec builder. +type Option func(*builder) + +// WithDeviceSpecs sets the device specs for the spec builder +func WithDeviceSpecs(deviceSpecs []cdi.Device) Option { + return func(o *builder) { + o.deviceSpecs = deviceSpecs + } +} + +// WithEdits sets the container edits for the spec builder +func WithEdits(edits cdi.ContainerEdits) Option { + return func(o *builder) { + o.edits = edits + } +} + +// WithVersion sets the version for the spec builder +func WithVersion(version string) Option { + return func(o *builder) { + o.version = version + } +} + +// WithVendor sets the vendor for the spec builder +func WithVendor(vendor string) Option { + return func(o *builder) { + o.vendor = vendor + } +} + +// WithClass sets the class for the spec builder +func WithClass(class string) Option { + return func(o *builder) { + o.class = class + } +} + +// WithFormat sets the output file format +func WithFormat(format string) Option { + return func(o *builder) { + o.format = format + } +} + +// WithNoSimplify sets whether the spec must be simplified +func WithNoSimplify(noSimplify bool) Option { + return func(o *builder) { + o.noSimplify = noSimplify + } +} + +// WithRawSpec sets the raw spec for the spec builder +func WithRawSpec(raw *cdi.Spec) Option { + return func(o *builder) { + o.raw = raw + } +} + +// WithPermissions sets the permissions for the generated spec file +func WithPermissions(permissions os.FileMode) Option { + return func(o *builder) { + o.permissions = permissions + } +} + +// WithMergedDeviceOptions sets the options for generating a merged device. +func WithMergedDeviceOptions(opts ...transform.MergedDeviceOption) Option { + return func(o *builder) { + o.mergedDeviceOptions = opts + } +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/set-minimum-version.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/set-minimum-version.go new file mode 100644 index 00000000..69969c0b --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/set-minimum-version.go @@ -0,0 +1,35 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package spec + +import ( + "fmt" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" +) + +type setMinimumRequiredVersion struct{} + +func (d setMinimumRequiredVersion) Transform(spec *specs.Spec) error { + minVersion, err := cdi.MinimumRequiredVersion(spec) + if err != nil { + return fmt.Errorf("failed to get minimum required CDI spec version: %v", err) + } + spec.Version = minVersion + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/spec.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/spec.go new file mode 100644 index 00000000..28cccc51 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec/spec.go @@ -0,0 +1,137 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package spec + +import ( + "fmt" + "io" + "os" + "path/filepath" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" +) + +type spec struct { + *specs.Spec + format string + permissions os.FileMode + transformOnSave transform.Transformer +} + +var _ Interface = (*spec)(nil) + +// New creates a new spec with the specified options. +func New(opts ...Option) (Interface, error) { + return newBuilder(opts...).Build() +} + +// Save writes the spec to the specified path and overwrites the file if it exists. +func (s *spec) Save(path string) error { + if s.transformOnSave != nil { + err := s.transformOnSave.Transform(s.Raw()) + if err != nil { + return fmt.Errorf("error applying transform: %w", err) + } + } + path, err := s.normalizePath(path) + if err != nil { + return fmt.Errorf("failed to normalize path: %w", err) + } + + specDir := filepath.Dir(path) + cache, _ := cdi.NewCache( + cdi.WithAutoRefresh(false), + cdi.WithSpecDirs(specDir), + ) + if err := cache.WriteSpec(s.Raw(), filepath.Base(path)); err != nil { + return fmt.Errorf("failed to write spec: %w", err) + } + + if err := os.Chmod(path, s.permissions); err != nil { + return fmt.Errorf("failed to set permissions on spec file: %w", err) + } + + return nil +} + +// WriteTo writes the spec to the specified writer. +func (s *spec) WriteTo(w io.Writer) (int64, error) { + name, err := cdi.GenerateNameForSpec(s.Raw()) + if err != nil { + return 0, err + } + + path, _ := s.normalizePath(name) + tmpFile, err := os.CreateTemp("", "*"+filepath.Base(path)) + if err != nil { + return 0, err + } + defer os.Remove(tmpFile.Name()) + + if err := s.Save(tmpFile.Name()); err != nil { + return 0, err + } + + err = tmpFile.Close() + if err != nil { + return 0, fmt.Errorf("failed to close temporary file: %w", err) + } + + r, err := os.Open(tmpFile.Name()) + if err != nil { + return 0, fmt.Errorf("failed to open temporary file: %w", err) + } + defer r.Close() + + return io.Copy(w, r) +} + +// Raw returns a pointer to the raw spec. +func (s *spec) Raw() *specs.Spec { + return s.Spec +} + +// normalizePath ensures that the specified path has a supported extension +func (s *spec) normalizePath(path string) (string, error) { + if ext := filepath.Ext(path); ext != ".yaml" && ext != ".json" { + path += s.extension() + } + + if filepath.Clean(filepath.Dir(path)) == "." { + pwd, err := os.Getwd() + if err != nil { + return path, fmt.Errorf("failed to get current working directory: %v", err) + } + path = filepath.Join(pwd, path) + } + + return path, nil +} + +func (s *spec) extension() string { + switch s.format { + case FormatJSON: + return ".json" + case FormatYAML: + return ".yaml" + } + + return ".yaml" +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/api.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/api.go new file mode 100644 index 00000000..786ffb46 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/api.go @@ -0,0 +1,24 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package transform + +import "tags.cncf.io/container-device-interface/specs-go" + +// Transformer defines the API for applying arbitrary transforms to a spec in-place +type Transformer interface { + Transform(*specs.Spec) error +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/deduplicate.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/deduplicate.go new file mode 100644 index 00000000..27be1b67 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/deduplicate.go @@ -0,0 +1,152 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package transform + +import ( + "tags.cncf.io/container-device-interface/specs-go" +) + +type dedupe struct{} + +var _ Transformer = (*dedupe)(nil) + +// NewDedupe creates a transformer that deduplicates container edits. +func NewDedupe() (Transformer, error) { + return &dedupe{}, nil +} + +// Transform removes duplicate entris from devices and common container edits. +func (d dedupe) Transform(spec *specs.Spec) error { + if spec == nil { + return nil + } + if err := d.transformEdits(&spec.ContainerEdits); err != nil { + return err + } + var updatedDevices []specs.Device + for _, device := range spec.Devices { + device := device + if err := d.transformEdits(&device.ContainerEdits); err != nil { + return err + } + updatedDevices = append(updatedDevices, device) + } + spec.Devices = updatedDevices + return nil +} + +func (d dedupe) transformEdits(edits *specs.ContainerEdits) error { + deviceNodes, err := d.deduplicateDeviceNodes(edits.DeviceNodes) + if err != nil { + return err + } + edits.DeviceNodes = deviceNodes + + envs, err := d.deduplicateEnvs(edits.Env) + if err != nil { + return err + } + edits.Env = envs + + hooks, err := d.deduplicateHooks(edits.Hooks) + if err != nil { + return err + } + edits.Hooks = hooks + + mounts, err := d.deduplicateMounts(edits.Mounts) + if err != nil { + return err + } + edits.Mounts = mounts + + return nil +} + +func (d dedupe) deduplicateDeviceNodes(entities []*specs.DeviceNode) ([]*specs.DeviceNode, error) { + seen := make(map[string]bool) + var deviceNodes []*specs.DeviceNode + for _, e := range entities { + if e == nil { + continue + } + id, err := deviceNode(*e).id() + if err != nil { + return nil, err + } + if seen[id] { + continue + } + seen[id] = true + deviceNodes = append(deviceNodes, e) + } + return deviceNodes, nil +} + +func (d dedupe) deduplicateEnvs(entities []string) ([]string, error) { + seen := make(map[string]bool) + var envs []string + for _, e := range entities { + id := e + if seen[id] { + continue + } + seen[id] = true + envs = append(envs, e) + } + return envs, nil +} + +func (d dedupe) deduplicateHooks(entities []*specs.Hook) ([]*specs.Hook, error) { + seen := make(map[string]bool) + var hooks []*specs.Hook + for _, e := range entities { + if e == nil { + continue + } + id, err := hook(*e).id() + if err != nil { + return nil, err + } + if seen[id] { + continue + } + seen[id] = true + hooks = append(hooks, e) + } + return hooks, nil +} + +func (d dedupe) deduplicateMounts(entities []*specs.Mount) ([]*specs.Mount, error) { + seen := make(map[string]bool) + var mounts []*specs.Mount + for _, e := range entities { + if e == nil { + continue + } + id, err := mount(*e).id() + if err != nil { + return nil, err + } + if seen[id] { + continue + } + seen[id] = true + mounts = append(mounts, e) + } + return mounts, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/edits.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/edits.go new file mode 100644 index 00000000..fea47ffa --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/edits.go @@ -0,0 +1,166 @@ +/* +* +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package transform + +import ( + "encoding/json" + + "tags.cncf.io/container-device-interface/specs-go" +) + +type containerEdits specs.ContainerEdits + +// IsEmpty returns true if the edits are empty. +func (e containerEdits) IsEmpty() bool { + // Devices with empty edits are invalid + if len(e.DeviceNodes) > 0 { + return false + } + if len(e.Env) > 0 { + return false + } + if len(e.Hooks) > 0 { + return false + } + if len(e.Mounts) > 0 { + return false + } + + return true +} + +func (e *containerEdits) getEntityIds() ([]string, error) { + if e == nil { + return nil, nil + } + uniqueIDs := make(map[string]bool) + + deviceNodes, err := e.getDeviceNodeIDs() + if err != nil { + return nil, err + } + for k := range deviceNodes { + uniqueIDs[k] = true + } + + envs, err := e.getEnvIDs() + if err != nil { + return nil, err + } + for k := range envs { + uniqueIDs[k] = true + } + + hooks, err := e.getHookIDs() + if err != nil { + return nil, err + } + for k := range hooks { + uniqueIDs[k] = true + } + + mounts, err := e.getMountIDs() + if err != nil { + return nil, err + } + for k := range mounts { + uniqueIDs[k] = true + } + + var ids []string + for k := range uniqueIDs { + ids = append(ids, k) + } + + return ids, nil +} + +func (e *containerEdits) getDeviceNodeIDs() (map[string]bool, error) { + deviceIDs := make(map[string]bool) + for _, entity := range e.DeviceNodes { + id, err := deviceNode(*entity).id() + if err != nil { + return nil, err + } + deviceIDs[id] = true + } + return deviceIDs, nil +} + +func (e *containerEdits) getEnvIDs() (map[string]bool, error) { + envIDs := make(map[string]bool) + for _, entity := range e.Env { + id, err := env(entity).id() + if err != nil { + return nil, err + } + envIDs[id] = true + } + return envIDs, nil +} + +func (e *containerEdits) getHookIDs() (map[string]bool, error) { + hookIDs := make(map[string]bool) + for _, entity := range e.Hooks { + id, err := hook(*entity).id() + if err != nil { + return nil, err + } + hookIDs[id] = true + } + return hookIDs, nil +} + +func (e *containerEdits) getMountIDs() (map[string]bool, error) { + mountIDs := make(map[string]bool) + for _, entity := range e.Mounts { + id, err := mount(*entity).id() + if err != nil { + return nil, err + } + mountIDs[id] = true + } + return mountIDs, nil +} + +type deviceNode specs.DeviceNode + +func (dn deviceNode) id() (string, error) { + b, err := json.Marshal(dn) + return string(b), err +} + +type env string + +func (e env) id() (string, error) { + return string(e), nil +} + +type mount specs.Mount + +func (m mount) id() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} + +type hook specs.Hook + +func (m hook) id() (string, error) { + b, err := json.Marshal(m) + return string(b), err +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/merge.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/merge.go new file mode 100644 index 00000000..762107b3 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/merge.go @@ -0,0 +1,36 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package transform + +import "tags.cncf.io/container-device-interface/specs-go" + +type merged []Transformer + +// Merge creates a merged transofrmer from the specified transformers. +func Merge(transformers ...Transformer) Transformer { + return merged(transformers) +} + +// Transform applies all the transformers in the merged set. +func (t merged) Transform(spec *specs.Spec) error { + for _, transformer := range t { + if err := transformer.Transform(spec); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/merged-device.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/merged-device.go new file mode 100644 index 00000000..523876e3 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/merged-device.go @@ -0,0 +1,126 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package transform + +import ( + "fmt" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/edits" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/pkg/parser" + "tags.cncf.io/container-device-interface/specs-go" +) + +const ( + allDeviceName = "all" +) + +type mergedDevice struct { + name string + skipIfExists bool + simplifier Transformer +} + +var _ Transformer = (*mergedDevice)(nil) + +// MergedDeviceOption is a function that configures a merged device +type MergedDeviceOption func(*mergedDevice) + +// WithName sets the name of the merged device +func WithName(name string) MergedDeviceOption { + return func(m *mergedDevice) { + m.name = name + } +} + +// WithSkipIfExists sets whether to skip adding the merged device if it already exists +func WithSkipIfExists(skipIfExists bool) MergedDeviceOption { + return func(m *mergedDevice) { + m.skipIfExists = skipIfExists + } +} + +// NewMergedDevice creates a transformer with the specified options +func NewMergedDevice(opts ...MergedDeviceOption) (Transformer, error) { + m := &mergedDevice{} + for _, opt := range opts { + opt(m) + } + if m.name == "" { + m.name = allDeviceName + } + m.simplifier = NewSimplifier() + + if err := parser.ValidateDeviceName(m.name); err != nil { + return nil, fmt.Errorf("invalid device name %q: %v", m.name, err) + } + + return m, nil +} + +// Transform adds a merged device to the spec +func (m mergedDevice) Transform(spec *specs.Spec) error { + if spec == nil { + return nil + } + + mergedDevice, err := mergeDeviceSpecs(spec.Devices, m.name) + if err != nil { + return fmt.Errorf("failed to generate merged device %q: %v", m.name, err) + } + if mergedDevice == nil { + if m.skipIfExists { + return nil + } + return fmt.Errorf("device %q already exists", m.name) + } + + spec.Devices = append(spec.Devices, *mergedDevice) + + if err := m.simplifier.Transform(spec); err != nil { + return fmt.Errorf("failed to simplify spec after merging device %q: %v", m.name, err) + } + + return nil +} + +// mergeDeviceSpecs creates a device with the specified name which combines the edits from the previous devices. +// If a device of the specified name already exists, no device is created and nil is returned. +func mergeDeviceSpecs(deviceSpecs []specs.Device, mergedDeviceName string) (*specs.Device, error) { + for _, d := range deviceSpecs { + if d.Name == mergedDeviceName { + return nil, nil + } + } + + mergedEdits := edits.NewContainerEdits() + + for _, d := range deviceSpecs { + d := d + edit := cdi.ContainerEdits{ + ContainerEdits: &d.ContainerEdits, + } + mergedEdits.Append(&edit) + } + + merged := specs.Device{ + Name: mergedDeviceName, + ContainerEdits: *mergedEdits.ContainerEdits, + } + return &merged, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/noop/no-op.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/noop/no-op.go new file mode 100644 index 00000000..8b7fe890 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/noop/no-op.go @@ -0,0 +1,37 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package noop + +import ( + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" +) + +type noop struct{} + +var _ transform.Transformer = (*noop)(nil) + +// New returns a no-op transformer. +func New() transform.Transformer { + return noop{} +} + +// Transform is a no-op for a noop transformer. +func (n noop) Transform(spec *specs.Spec) error { + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/remove.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/remove.go new file mode 100644 index 00000000..bc009485 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/remove.go @@ -0,0 +1,106 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package transform + +import ( + "fmt" + + "tags.cncf.io/container-device-interface/specs-go" +) + +type remove map[string]bool + +func newRemover(ids ...string) Transformer { + r := make(remove) + for _, id := range ids { + r[id] = true + } + return r +} + +// Transform remove the specified entities from the spec. +func (r remove) Transform(spec *specs.Spec) error { + if spec == nil { + return nil + } + + for _, device := range spec.Devices { + device := device + if err := r.transformEdits(&device.ContainerEdits); err != nil { + return fmt.Errorf("failed to remove edits from device %q: %w", device.Name, err) + } + } + + return r.transformEdits(&spec.ContainerEdits) +} + +func (r remove) transformEdits(edits *specs.ContainerEdits) error { + if edits == nil { + return nil + } + + var deviceNodes []*specs.DeviceNode + for _, entity := range edits.DeviceNodes { + id, err := deviceNode(*entity).id() + if err != nil { + return err + } + if r[id] { + continue + } + deviceNodes = append(deviceNodes, entity) + } + edits.DeviceNodes = deviceNodes + + var envs []string + for _, entity := range edits.Env { + id := entity + if r[id] { + continue + } + envs = append(envs, entity) + } + edits.Env = envs + + var hooks []*specs.Hook + for _, entity := range edits.Hooks { + id, err := hook(*entity).id() + if err != nil { + return err + } + if r[id] { + continue + } + hooks = append(hooks, entity) + } + edits.Hooks = hooks + + var mounts []*specs.Mount + for _, entity := range edits.Mounts { + id, err := mount(*entity).id() + if err != nil { + return err + } + if r[id] { + continue + } + mounts = append(mounts, entity) + } + edits.Mounts = mounts + + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/builder.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/builder.go new file mode 100644 index 00000000..7ac7b7b8 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/builder.go @@ -0,0 +1,38 @@ +/** +# Copyright 2023 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package root + +import ( + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/noop" +) + +type builder struct { + transformer + relativeTo string +} + +func (b *builder) build() transform.Transformer { + if b.root == b.targetRoot { + return noop.New() + } + + if b.relativeTo == "container" { + return containerRootTransformer(b.transformer) + } + return hostRootTransformer(b.transformer) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/container-root.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/container-root.go new file mode 100644 index 00000000..b8d76f92 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/container-root.go @@ -0,0 +1,113 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package root + +import ( + "fmt" + "strings" + + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" +) + +// containerRootTransformer transforms the roots of container paths in a CDI spec. +type containerRootTransformer transformer + +var _ transform.Transformer = (*containerRootTransformer)(nil) + +// Transform replaces the root in a spec with a new root. +// It walks the spec and replaces all container paths that start with root with the target root. +func (t containerRootTransformer) Transform(spec *specs.Spec) error { + if spec == nil { + return nil + } + + for _, d := range spec.Devices { + d := d + if err := t.applyToEdits(&d.ContainerEdits); err != nil { + return fmt.Errorf("failed to apply root transform to device %s: %w", d.Name, err) + } + } + + if err := t.applyToEdits(&spec.ContainerEdits); err != nil { + return fmt.Errorf("failed to apply root transform to spec: %w", err) + } + return nil +} + +func (t containerRootTransformer) applyToEdits(edits *specs.ContainerEdits) error { + for i, dn := range edits.DeviceNodes { + edits.DeviceNodes[i] = t.transformDeviceNode(dn) + } + + for i, hook := range edits.Hooks { + edits.Hooks[i] = t.transformHook(hook) + } + + for i, mount := range edits.Mounts { + edits.Mounts[i] = t.transformMount(mount) + } + + return nil +} + +func (t containerRootTransformer) transformDeviceNode(dn *specs.DeviceNode) *specs.DeviceNode { + dn.Path = t.transformPath(dn.Path) + + return dn +} + +func (t containerRootTransformer) transformHook(hook *specs.Hook) *specs.Hook { + // The Path in the startContainer hook MUST resolve in the container namespace. + if hook.HookName == "startContainer" { + hook.Path = t.transformPath(hook.Path) + } + + // The createContainer and startContainer hooks MUST execute in the container namespace. + if hook.HookName != "createContainer" && hook.HookName != "startContainer" { + return hook + } + + var args []string + for _, arg := range hook.Args { + if !strings.Contains(arg, "::") { + args = append(args, t.transformPath(arg)) + continue + } + + // For the 'create-symlinks' hook, special care is taken for the + // '--link' flag argument which takes the form ::. + // Both paths, the target and link paths, are transformed. + split := strings.SplitN(arg, "::", 2) + split[0] = t.transformPath(split[0]) + split[1] = t.transformPath(split[1]) + args = append(args, strings.Join(split, "::")) + } + hook.Args = args + + return hook +} + +func (t containerRootTransformer) transformMount(mount *specs.Mount) *specs.Mount { + mount.ContainerPath = t.transformPath(mount.ContainerPath) + return mount +} + +func (t containerRootTransformer) transformPath(path string) string { + return (transformer)(t).transformPath(path) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/driver-root.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/driver-root.go new file mode 100644 index 00000000..931e73ef --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/driver-root.go @@ -0,0 +1,99 @@ +/** +# Copyright 2024 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package root + +import ( + "path/filepath" + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" +) + +type DriverOption func(*driverOptions) + +func WithDriverRoot(root string) DriverOption { + return func(do *driverOptions) { + do.driverRoot = root + } +} + +func WithTargetDriverRoot(root string) DriverOption { + return func(do *driverOptions) { + do.targetDriverRoot = root + } +} + +func WithDevRoot(root string) DriverOption { + return func(do *driverOptions) { + do.devRoot = root + } +} + +func WithTargetDevRoot(root string) DriverOption { + return func(do *driverOptions) { + do.targetDevRoot = root + } +} + +type driverOptions struct { + driverRoot string + targetDriverRoot string + devRoot string + targetDevRoot string +} + +// NewDriverTransformer creates a transformer for transforming driver specifications. +func NewDriverTransformer(opts ...DriverOption) transform.Transformer { + d := &driverOptions{} + for _, opt := range opts { + opt(d) + } + if d.driverRoot == "" { + d.driverRoot = "/" + } + if d.targetDriverRoot == "" { + d.targetDriverRoot = "/" + } + if d.devRoot == "" { + d.devRoot = d.driverRoot + } + if d.targetDevRoot == "" { + d.targetDevRoot = d.targetDriverRoot + } + + var transformers []transform.Transformer + + if d.targetDevRoot != d.targetDriverRoot { + devRootTransformer := New( + WithRoot(ensureDev(d.devRoot)), + WithTargetRoot(ensureDev(d.targetDevRoot)), + ) + transformers = append(transformers, devRootTransformer) + } + + driverRootTransformer := New( + WithRoot(d.driverRoot), + WithTargetRoot(d.targetDriverRoot), + ) + transformers = append(transformers, driverRootTransformer) + + return transform.Merge(transformers...) +} + +func ensureDev(p string) string { + return filepath.Join(strings.TrimSuffix(filepath.Clean(p), "/dev"), "/dev") +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/host-root.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/host-root.go new file mode 100644 index 00000000..9d2b54d3 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/host-root.go @@ -0,0 +1,116 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package root + +import ( + "fmt" + "strings" + + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" +) + +// hostRootTransformer transforms the roots of host paths in a CDI spec. +type hostRootTransformer transformer + +var _ transform.Transformer = (*hostRootTransformer)(nil) + +// Transform replaces the root in a spec with a new root. +// It walks the spec and replaces all host paths that start with root with the target root. +func (t hostRootTransformer) Transform(spec *specs.Spec) error { + if spec == nil { + return nil + } + + for _, d := range spec.Devices { + d := d + if err := t.applyToEdits(&d.ContainerEdits); err != nil { + return fmt.Errorf("failed to apply root transform to device %s: %w", d.Name, err) + } + } + + if err := t.applyToEdits(&spec.ContainerEdits); err != nil { + return fmt.Errorf("failed to apply root transform to spec: %w", err) + } + return nil +} + +func (t hostRootTransformer) applyToEdits(edits *specs.ContainerEdits) error { + for i, dn := range edits.DeviceNodes { + edits.DeviceNodes[i] = t.transformDeviceNode(dn) + } + + for i, hook := range edits.Hooks { + edits.Hooks[i] = t.transformHook(hook) + } + + for i, mount := range edits.Mounts { + edits.Mounts[i] = t.transformMount(mount) + } + + return nil +} + +func (t hostRootTransformer) transformDeviceNode(dn *specs.DeviceNode) *specs.DeviceNode { + if dn.HostPath == "" { + dn.HostPath = dn.Path + } + dn.HostPath = t.transformPath(dn.HostPath) + + return dn +} + +func (t hostRootTransformer) transformHook(hook *specs.Hook) *specs.Hook { + // The Path in the startContainer hook MUST resolve in the container namespace. + if hook.HookName != "startContainer" { + hook.Path = t.transformPath(hook.Path) + } + + // The createContainer and startContainer hooks MUST execute in the container namespace. + if hook.HookName == "createContainer" || hook.HookName == "startContainer" { + return hook + } + + var args []string + for _, arg := range hook.Args { + if !strings.Contains(arg, "::") { + args = append(args, t.transformPath(arg)) + continue + } + + // For the 'create-symlinks' hook, special care is taken for the + // '--link' flag argument which takes the form ::. + // Both paths, the target and link paths, are transformed. + split := strings.SplitN(arg, "::", 2) + split[0] = t.transformPath(split[0]) + split[1] = t.transformPath(split[1]) + args = append(args, strings.Join(split, "::")) + } + hook.Args = args + + return hook +} + +func (t hostRootTransformer) transformMount(mount *specs.Mount) *specs.Mount { + mount.HostPath = t.transformPath(mount.HostPath) + return mount +} + +func (t hostRootTransformer) transformPath(path string) string { + return (transformer)(t).transformPath(path) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/options.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/options.go new file mode 100644 index 00000000..1b9d5aba --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/options.go @@ -0,0 +1,41 @@ +/** +# Copyright 2023 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package root + +// Option defines a functional option for configuring a transormer. +type Option func(*builder) + +// WithRoot sets the (from) root for the root transformer. +func WithRoot(root string) Option { + return func(b *builder) { + b.root = root + } +} + +// WithTargetRoot sets the (to) target root for the root transformer. +func WithTargetRoot(root string) Option { + return func(b *builder) { + b.targetRoot = root + } +} + +// WithRelativeTo sets whether the specified root is relative to the host or container. +func WithRelativeTo(relativeTo string) Option { + return func(b *builder) { + b.relativeTo = relativeTo + } +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/root.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/root.go new file mode 100644 index 00000000..36203fba --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root/root.go @@ -0,0 +1,47 @@ +/** +# Copyright 2023 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package root + +import ( + "path/filepath" + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" +) + +// transformer transforms roots of paths. +type transformer struct { + root string + targetRoot string +} + +// New creates a root transformer using the specified options. +func New(opts ...Option) transform.Transformer { + b := &builder{} + for _, opt := range opts { + opt(b) + } + return b.build() +} + +func (t transformer) transformPath(path string) string { + if !strings.HasPrefix(path, t.root) { + return path + } + + return filepath.Join(t.targetRoot, strings.TrimPrefix(path, t.root)) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/simplify.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/simplify.go new file mode 100644 index 00000000..23bdfed8 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/simplify.go @@ -0,0 +1,78 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package transform + +import ( + "fmt" + + "tags.cncf.io/container-device-interface/specs-go" +) + +type simplify struct{} + +var _ Transformer = (*simplify)(nil) + +// NewSimplifier creates a simplifier transformer. +// This transoformer ensures that entities in the spec are deduplicated and that common edits are removed from device-specific edits. +func NewSimplifier() Transformer { + return Merge( + dedupe{}, + simplify{}, + sorter{}, + ) +} + +// Transform simplifies the supplied spec. +// Edits that are present in the common edits are removed from device-specific edits. +func (s simplify) Transform(spec *specs.Spec) error { + if spec == nil { + return nil + } + + dedupe := dedupe{} + if err := dedupe.Transform(spec); err != nil { + return err + } + + commonEntityIDs, err := (*containerEdits)(&spec.ContainerEdits).getEntityIds() + if err != nil { + return err + } + + toRemove := newRemover(commonEntityIDs...) + var updatedDevices []specs.Device + for _, device := range spec.Devices { + deviceAsSpec := specs.Spec{ + ContainerEdits: device.ContainerEdits, + } + err := toRemove.Transform(&deviceAsSpec) + if err != nil { + return fmt.Errorf("failed to transform device edits: %w", err) + } + + if !(containerEdits)(deviceAsSpec.ContainerEdits).IsEmpty() { + // Devices with empty edits are invalid. + // We only update the container edits for the device if this would + // result in a valid device. + device.ContainerEdits = deviceAsSpec.ContainerEdits + } + updatedDevices = append(updatedDevices, device) + } + spec.Devices = updatedDevices + + return nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/sorter.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/sorter.go new file mode 100644 index 00000000..2fc53ac3 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/sorter.go @@ -0,0 +1,96 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package transform + +import ( + "os" + "path/filepath" + "sort" + "strings" + + "tags.cncf.io/container-device-interface/specs-go" +) + +type sorter struct{} + +var _ Transformer = (*sorter)(nil) + +// NewSorter creates a transformer that sorts container edits. +func NewSorter() Transformer { + return nil +} + +// Transform sorts the entities in the specified CDI specification. +func (d sorter) Transform(spec *specs.Spec) error { + if spec == nil { + return nil + } + if err := d.transformEdits(&spec.ContainerEdits); err != nil { + return err + } + var updatedDevices []specs.Device + for _, device := range spec.Devices { + device := device + if err := d.transformEdits(&device.ContainerEdits); err != nil { + return err + } + updatedDevices = append(updatedDevices, device) + } + spec.Devices = d.sortDevices(updatedDevices) + return nil +} + +func (d sorter) transformEdits(edits *specs.ContainerEdits) error { + edits.DeviceNodes = d.sortDeviceNodes(edits.DeviceNodes) + edits.Mounts = d.sortMounts(edits.Mounts) + return nil +} + +func (d sorter) sortDevices(devices []specs.Device) []specs.Device { + sort.Slice(devices, func(i, j int) bool { + return devices[i].Name < devices[j].Name + }) + return devices +} + +// sortDeviceNodes sorts the specified device nodes by container path. +// If two device nodes have the same container path, the host path is used to break ties. +func (d sorter) sortDeviceNodes(entities []*specs.DeviceNode) []*specs.DeviceNode { + sort.Slice(entities, func(i, j int) bool { + ip := strings.Count(filepath.Clean(entities[i].Path), string(os.PathSeparator)) + jp := strings.Count(filepath.Clean(entities[j].Path), string(os.PathSeparator)) + if ip == jp { + return entities[i].Path < entities[j].Path + } + return ip < jp + }) + return entities +} + +// sortMounts sorts the specified mounts by container path. +// If two mounts have the same mount path, the host path is used to break ties. +func (d sorter) sortMounts(entities []*specs.Mount) []*specs.Mount { + sort.Slice(entities, func(i, j int) bool { + ip := strings.Count(filepath.Clean(entities[i].ContainerPath), string(os.PathSeparator)) + jp := strings.Count(filepath.Clean(entities[j].ContainerPath), string(os.PathSeparator)) + if ip == jp { + return entities[i].ContainerPath < entities[j].ContainerPath + } + return ip < jp + }) + return entities +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/workarounds-device-folder-permissions.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/workarounds-device-folder-permissions.go new file mode 100644 index 00000000..49a79648 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/workarounds-device-folder-permissions.go @@ -0,0 +1,110 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + "path/filepath" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/discover" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +type deviceFolderPermissions struct { + logger logger.Interface + devRoot string + devices discover.Discover + hookCreator discover.HookCreator +} + +var _ discover.Discover = (*deviceFolderPermissions)(nil) + +// newDeviceFolderPermissionHookDiscoverer creates a discoverer that can be used to update the permissions for the parent folders of nested device nodes from the specified set of device specs. +// This works around an issue with rootless podman when using crun as a low-level runtime. +// See https://github.com/containers/crun/issues/1047 +// The nested devices that are applicable to the NVIDIA GPU devices are: +// - DRM devices at /dev/dri/* +// - NVIDIA Caps devices at /dev/nvidia-caps/* +func newDeviceFolderPermissionHookDiscoverer(logger logger.Interface, devRoot string, hookCreator discover.HookCreator, devices discover.Discover) discover.Discover { + d := &deviceFolderPermissions{ + logger: logger, + devRoot: devRoot, + hookCreator: hookCreator, + devices: devices, + } + + return d +} + +// Devices are empty for this discoverer +func (d *deviceFolderPermissions) Devices() ([]discover.Device, error) { + return nil, nil +} + +// EnvVars are empty for this discoverer +func (d *deviceFolderPermissions) EnvVars() ([]discover.EnvVar, error) { + return nil, nil +} + +// Hooks returns a set of hooks that sets the file mode to 755 of parent folders for nested device nodes. +func (d *deviceFolderPermissions) Hooks() ([]discover.Hook, error) { + folders, err := d.getDeviceSubfolders() + if err != nil { + return nil, fmt.Errorf("failed to get device subfolders: %v", err) + } + + //nolint:staticcheck // The ChmodHook is deprecated and will be removed in a future release. + return d.hookCreator.Create(discover.ChmodHook, folders...).Hooks() +} + +func (d *deviceFolderPermissions) getDeviceSubfolders() ([]string, error) { + // For now we only consider the following special case paths + allowedPaths := map[string]bool{ + "/dev/dri": true, + "/dev/nvidia-caps": true, + } + + devices, err := d.devices.Devices() + if err != nil { + return nil, fmt.Errorf("failed to get devices: %v", err) + } + + var folders []string + seen := make(map[string]bool) + for _, device := range devices { + df := filepath.Dir(device.Path) + if seen[df] { + continue + } + // We only consider the special case paths + if !allowedPaths[df] { + continue + } + folders = append(folders, df) + seen[df] = true + if len(folders) == len(allowedPaths) { + break + } + } + + return folders, nil +} + +// Mounts are empty for this discoverer +func (d *deviceFolderPermissions) Mounts() ([]discover.Mount, error) { + return nil, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/wrapper.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/wrapper.go new file mode 100644 index 00000000..9d452079 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/wrapper.go @@ -0,0 +1,119 @@ +/** +# Copyright 2025 NVIDIA CORPORATION +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvcdi + +import ( + "fmt" + + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/config/image" + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec" + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform" +) + +type wrapper struct { + factory deviceSpecGeneratorFactory + + vendor string + class string + + mergedDeviceOptions []transform.MergedDeviceOption +} + +// TODO: Rename this type +type deviceSpecGeneratorFactory interface { + DeviceSpecGenerators(...string) (DeviceSpecGenerator, error) + GetCommonEdits() (*cdi.ContainerEdits, error) +} + +// DeviceSpecGenerators can be used to combine multiple device spec generators. +// This type also implements the DeviceSpecGenerator interface. +type DeviceSpecGenerators []DeviceSpecGenerator + +var _ DeviceSpecGenerator = (DeviceSpecGenerators)(nil) + +// GetSpec combines the device specs and common edits from the wrapped Interface to a single spec.Interface. +func (l *wrapper) GetSpec(devices ...string) (spec.Interface, error) { + if len(devices) == 0 { + devices = append(devices, "all") + } + deviceSpecs, err := l.GetDeviceSpecsByID(devices...) + if err != nil { + return nil, err + } + + edits, err := l.GetCommonEdits() + if err != nil { + return nil, err + } + + return spec.New( + spec.WithDeviceSpecs(deviceSpecs), + spec.WithEdits(*edits.ContainerEdits), + spec.WithVendor(l.vendor), + spec.WithClass(l.class), + spec.WithMergedDeviceOptions(l.mergedDeviceOptions...), + ) +} + +// GetDeviceSpecsByID returns the CDI device specs for devices with the +// specified IDs. +// The device IDs are interpreted by the configured factory. +func (l *wrapper) GetDeviceSpecsByID(devices ...string) ([]specs.Device, error) { + generators, err := l.factory.DeviceSpecGenerators(devices...) + if err != nil { + return nil, fmt.Errorf("failed to construct device spec generators: %w", err) + } + return generators.GetDeviceSpecs() +} + +// GetAllDeviceSpecs returns the device specs for all available devices. +// +// Deprecated: Use GetDeviceSpecsByID("all") instead. +func (l *wrapper) GetAllDeviceSpecs() ([]specs.Device, error) { + return l.GetDeviceSpecsByID("all") +} + +// GetCommonEdits returns the wrapped edits and adds additional edits on top. +func (m *wrapper) GetCommonEdits() (*cdi.ContainerEdits, error) { + edits, err := m.factory.GetCommonEdits() + if err != nil { + return nil, err + } + edits.Env = append(edits.Env, image.EnvVarNvidiaVisibleDevices+"=void") + + return edits, nil +} + +// GetDeviceSpecs returns the combined specs for each device spec generator. +func (g DeviceSpecGenerators) GetDeviceSpecs() ([]specs.Device, error) { + var allDeviceSpecs []specs.Device + for _, dsg := range g { + if dsg == nil { + continue + } + deviceSpecs, err := dsg.GetDeviceSpecs() + if err != nil { + return nil, err + } + allDeviceSpecs = append(allDeviceSpecs, deviceSpecs...) + } + + return allDeviceSpecs, nil +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/devices.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/devices.go new file mode 100644 index 00000000..f667f6b7 --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/devices.go @@ -0,0 +1,146 @@ +/** +# Copyright (c) NVIDIA CORPORATIOm. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvdevices + +import ( + "errors" + "fmt" + "path/filepath" + "strings" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +var errInvalidDeviceNode = errors.New("invalid device node") + +// Interface provides a set of utilities for interacting with NVIDIA devices on the system. +type Interface struct { + devices.Devices + + logger logger.Interface + + dryRun bool + // devRoot is the root directory where device nodes are expected to exist. + devRoot string + + mknoder +} + +// New constructs a new Interface struct with the specified options. +func New(opts ...Option) (*Interface, error) { + i := &Interface{} + for _, opt := range opts { + opt(i) + } + + if i.logger == nil { + i.logger = logger.New() + } + if i.devRoot == "" { + i.devRoot = "/" + } + if i.Devices == nil { + devices, err := devices.GetNVIDIADevices() + if err != nil { + return nil, fmt.Errorf("failed to create devices info: %v", err) + } + i.Devices = devices + } + + if i.dryRun { + i.mknoder = &mknodLogger{i.logger} + } else { + i.mknoder = &mknodUnix{i.logger} + } + return i, nil +} + +// CreateNVIDIAControlDevices creates the NVIDIA control device nodes at the configured devRoot. +func (m *Interface) CreateNVIDIAControlDevices() error { + controlNodes := []string{"nvidiactl", "nvidia-modeset", "nvidia-uvm", "nvidia-uvm-tools"} + for _, node := range controlNodes { + err := m.CreateNVIDIADevice(node) + if err != nil { + return fmt.Errorf("failed to create device node %s: %w", node, err) + } + } + return nil +} + +// CreateNVIDIADevice creates the specified NVIDIA device node at the configured devRoot. +func (m *Interface) CreateNVIDIADevice(node string) error { + node = filepath.Base(node) + if !strings.HasPrefix(node, "nvidia") { + return fmt.Errorf("invalid device node %q: %w", node, errInvalidDeviceNode) + } + + major, err := m.Major(node) + if err != nil { + return fmt.Errorf("failed to determine major: %w", err) + } + + minor, err := m.Minor(node) + if err != nil { + return fmt.Errorf("failed to determine minor: %w", err) + } + + return m.createDeviceNode(filepath.Join("dev", node), int(major), int(minor)) +} + +// createDeviceNode creates the specified device node with the require major and minor numbers. +// If a devRoot is configured, this is prepended to the path. +func (m *Interface) createDeviceNode(path string, major int, minor int) error { + path = filepath.Join(m.devRoot, path) + return m.Mknode(path, major, minor) +} + +// Major returns the major number for the specified NVIDIA device node. +// If the device node is not supported, an error is returned. +func (m *Interface) Major(node string) (int64, error) { + var valid bool + var major devices.Major + switch node { + case "nvidia-uvm", "nvidia-uvm-tools": + major, valid = m.Get(devices.NVIDIAUVM) + case "nvidia-modeset", "nvidiactl": + major, valid = m.Get(devices.NVIDIAGPU) + } + + if valid { + return int64(major), nil + } + + return 0, errInvalidDeviceNode +} + +// Minor returns the minor number for the specified NVIDIA device node. +// If the device node is not supported, an error is returned. +func (m *Interface) Minor(node string) (int64, error) { + switch node { + case "nvidia-modeset": + return devices.NVIDIAModesetMinor, nil + case "nvidia-uvm-tools": + return devices.NVIDIAUVMToolsMinor, nil + case "nvidia-uvm": + return devices.NVIDIAUVMMinor, nil + case "nvidiactl": + return devices.NVIDIACTLMinor, nil + } + + return 0, errInvalidDeviceNode +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/mknod.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/mknod.go new file mode 100644 index 00000000..8cbec51d --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/mknod.go @@ -0,0 +1,60 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvdevices + +import ( + "fmt" + "os" + + "golang.org/x/sys/unix" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +//go:generate moq -rm -fmt=goimports -stub -out mknod_mock.go . mknoder +type mknoder interface { + Mknode(string, int, int) error +} + +type mknodLogger struct { + logger.Interface +} + +func (m *mknodLogger) Mknode(path string, major, minor int) error { + m.Infof("Running: mknod --mode=0666 %s c %d %d", path, major, minor) + return nil +} + +type mknodUnix struct { + logger logger.Interface +} + +func (m *mknodUnix) Mknode(path string, major, minor int) error { + // TODO: Ensure that the existing device node has the correct properties. + if _, err := os.Stat(path); err == nil { + m.logger.Infof("Skipping: %s already exists", path) + return nil + } else if !os.IsNotExist(err) { + return fmt.Errorf("failed to stat %s: %v", path, err) + } + + err := unix.Mknod(path, unix.S_IFCHR, int(unix.Mkdev(uint32(major), uint32(minor)))) + if err != nil { + return err + } + return unix.Chmod(path, 0666) +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/mknod_mock.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/mknod_mock.go new file mode 100644 index 00000000..4bb384fa --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/mknod_mock.go @@ -0,0 +1,89 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package nvdevices + +import ( + "sync" +) + +// Ensure, that mknoderMock does implement mknoder. +// If this is not the case, regenerate this file with moq. +var _ mknoder = &mknoderMock{} + +// mknoderMock is a mock implementation of mknoder. +// +// func TestSomethingThatUsesmknoder(t *testing.T) { +// +// // make and configure a mocked mknoder +// mockedmknoder := &mknoderMock{ +// MknodeFunc: func(s string, n1 int, n2 int) error { +// panic("mock out the Mknode method") +// }, +// } +// +// // use mockedmknoder in code that requires mknoder +// // and then make assertions. +// +// } +type mknoderMock struct { + // MknodeFunc mocks the Mknode method. + MknodeFunc func(s string, n1 int, n2 int) error + + // calls tracks calls to the methods. + calls struct { + // Mknode holds details about calls to the Mknode method. + Mknode []struct { + // S is the s argument value. + S string + // N1 is the n1 argument value. + N1 int + // N2 is the n2 argument value. + N2 int + } + } + lockMknode sync.RWMutex +} + +// Mknode calls MknodeFunc. +func (mock *mknoderMock) Mknode(s string, n1 int, n2 int) error { + callInfo := struct { + S string + N1 int + N2 int + }{ + S: s, + N1: n1, + N2: n2, + } + mock.lockMknode.Lock() + mock.calls.Mknode = append(mock.calls.Mknode, callInfo) + mock.lockMknode.Unlock() + if mock.MknodeFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.MknodeFunc(s, n1, n2) +} + +// MknodeCalls gets all the calls that were made to Mknode. +// Check the length with: +// +// len(mockedmknoder.MknodeCalls()) +func (mock *mknoderMock) MknodeCalls() []struct { + S string + N1 int + N2 int +} { + var calls []struct { + S string + N1 int + N2 int + } + mock.lockMknode.RLock() + calls = mock.calls.Mknode + mock.lockMknode.RUnlock() + return calls +} diff --git a/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/options.go b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/options.go new file mode 100644 index 00000000..0bcf319d --- /dev/null +++ b/vendor/github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices/options.go @@ -0,0 +1,53 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvdevices + +import ( + "github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices" + "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" +) + +// Option is a function that sets an option on the Interface struct. +type Option func(*Interface) + +// WithDryRun sets the dry run option for the Interface struct. +func WithDryRun(dryRun bool) Option { + return func(i *Interface) { + i.dryRun = dryRun + } +} + +// WithLogger sets the logger for the Interface struct. +func WithLogger(logger logger.Interface) Option { + return func(i *Interface) { + i.logger = logger + } +} + +// WithDevRoot sets the root directory for the NVIDIA device nodes. +func WithDevRoot(devRoot string) Option { + return func(i *Interface) { + i.devRoot = devRoot + } +} + +// WithDevices sets the devices for the Interface struct. +func WithDevices(devices devices.Devices) Option { + return func(i *Interface) { + i.Devices = devices + } +} diff --git a/vendor/github.com/fsnotify/fsnotify/.cirrus.yml b/vendor/github.com/fsnotify/fsnotify/.cirrus.yml new file mode 100644 index 00000000..ffc7b992 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.cirrus.yml @@ -0,0 +1,13 @@ +freebsd_task: + name: 'FreeBSD' + freebsd_instance: + image_family: freebsd-13-2 + install_script: + - pkg update -f + - pkg install -y go + test_script: + # run tests as user "cirrus" instead of root + - pw useradd cirrus -m + - chown -R cirrus:cirrus . + - FSNOTIFY_BUFFER=4096 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./... + - sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./... diff --git a/vendor/github.com/fsnotify/fsnotify/.editorconfig b/vendor/github.com/fsnotify/fsnotify/.editorconfig new file mode 100644 index 00000000..fad89585 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*.go] +indent_style = tab +indent_size = 4 +insert_final_newline = true + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/vendor/github.com/fsnotify/fsnotify/.gitattributes b/vendor/github.com/fsnotify/fsnotify/.gitattributes new file mode 100644 index 00000000..32f1001b --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.gitattributes @@ -0,0 +1 @@ +go.sum linguist-generated diff --git a/vendor/github.com/fsnotify/fsnotify/.gitignore b/vendor/github.com/fsnotify/fsnotify/.gitignore new file mode 100644 index 00000000..391cc076 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.gitignore @@ -0,0 +1,7 @@ +# go test -c output +*.test +*.test.exe + +# Output of go build ./cmd/fsnotify +/fsnotify +/fsnotify.exe diff --git a/vendor/github.com/fsnotify/fsnotify/.mailmap b/vendor/github.com/fsnotify/fsnotify/.mailmap new file mode 100644 index 00000000..a04f2907 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.mailmap @@ -0,0 +1,2 @@ +Chris Howey +Nathan Youngman <4566+nathany@users.noreply.github.com> diff --git a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md new file mode 100644 index 00000000..e0e57575 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md @@ -0,0 +1,541 @@ +# Changelog + +Unreleased +---------- +Nothing yet. + +1.7.0 - 2023-10-22 +------------------ +This version of fsnotify needs Go 1.17. + +### Additions + +- illumos: add FEN backend to support illumos and Solaris. ([#371]) + +- all: add `NewBufferedWatcher()` to use a buffered channel, which can be useful + in cases where you can't control the kernel buffer and receive a large number + of events in bursts. ([#550], [#572]) + +- all: add `AddWith()`, which is identical to `Add()` but allows passing + options. ([#521]) + +- windows: allow setting the ReadDirectoryChangesW() buffer size with + `fsnotify.WithBufferSize()`; the default of 64K is the highest value that + works on all platforms and is enough for most purposes, but in some cases a + highest buffer is needed. ([#521]) + +### Changes and fixes + +- inotify: remove watcher if a watched path is renamed ([#518]) + + After a rename the reported name wasn't updated, or even an empty string. + Inotify doesn't provide any good facilities to update it, so just remove the + watcher. This is already how it worked on kqueue and FEN. + + On Windows this does work, and remains working. + +- windows: don't listen for file attribute changes ([#520]) + + File attribute changes are sent as `FILE_ACTION_MODIFIED` by the Windows API, + with no way to see if they're a file write or attribute change, so would show + up as a fsnotify.Write event. This is never useful, and could result in many + spurious Write events. + +- windows: return `ErrEventOverflow` if the buffer is full ([#525]) + + Before it would merely return "short read", making it hard to detect this + error. + +- kqueue: make sure events for all files are delivered properly when removing a + watched directory ([#526]) + + Previously they would get sent with `""` (empty string) or `"."` as the path + name. + +- kqueue: don't emit spurious Create events for symbolic links ([#524]) + + The link would get resolved but kqueue would "forget" it already saw the link + itself, resulting on a Create for every Write event for the directory. + +- all: return `ErrClosed` on `Add()` when the watcher is closed ([#516]) + +- other: add `Watcher.Errors` and `Watcher.Events` to the no-op `Watcher` in + `backend_other.go`, making it easier to use on unsupported platforms such as + WASM, AIX, etc. ([#528]) + +- other: use the `backend_other.go` no-op if the `appengine` build tag is set; + Google AppEngine forbids usage of the unsafe package so the inotify backend + won't compile there. + +[#371]: https://github.com/fsnotify/fsnotify/pull/371 +[#516]: https://github.com/fsnotify/fsnotify/pull/516 +[#518]: https://github.com/fsnotify/fsnotify/pull/518 +[#520]: https://github.com/fsnotify/fsnotify/pull/520 +[#521]: https://github.com/fsnotify/fsnotify/pull/521 +[#524]: https://github.com/fsnotify/fsnotify/pull/524 +[#525]: https://github.com/fsnotify/fsnotify/pull/525 +[#526]: https://github.com/fsnotify/fsnotify/pull/526 +[#528]: https://github.com/fsnotify/fsnotify/pull/528 +[#537]: https://github.com/fsnotify/fsnotify/pull/537 +[#550]: https://github.com/fsnotify/fsnotify/pull/550 +[#572]: https://github.com/fsnotify/fsnotify/pull/572 + +1.6.0 - 2022-10-13 +------------------ +This version of fsnotify needs Go 1.16 (this was already the case since 1.5.1, +but not documented). It also increases the minimum Linux version to 2.6.32. + +### Additions + +- all: add `Event.Has()` and `Op.Has()` ([#477]) + + This makes checking events a lot easier; for example: + + if event.Op&Write == Write && !(event.Op&Remove == Remove) { + } + + Becomes: + + if event.Has(Write) && !event.Has(Remove) { + } + +- all: add cmd/fsnotify ([#463]) + + A command-line utility for testing and some examples. + +### Changes and fixes + +- inotify: don't ignore events for files that don't exist ([#260], [#470]) + + Previously the inotify watcher would call `os.Lstat()` to check if a file + still exists before emitting events. + + This was inconsistent with other platforms and resulted in inconsistent event + reporting (e.g. when a file is quickly removed and re-created), and generally + a source of confusion. It was added in 2013 to fix a memory leak that no + longer exists. + +- all: return `ErrNonExistentWatch` when `Remove()` is called on a path that's + not watched ([#460]) + +- inotify: replace epoll() with non-blocking inotify ([#434]) + + Non-blocking inotify was not generally available at the time this library was + written in 2014, but now it is. As a result, the minimum Linux version is + bumped from 2.6.27 to 2.6.32. This hugely simplifies the code and is faster. + +- kqueue: don't check for events every 100ms ([#480]) + + The watcher would wake up every 100ms, even when there was nothing to do. Now + it waits until there is something to do. + +- macos: retry opening files on EINTR ([#475]) + +- kqueue: skip unreadable files ([#479]) + + kqueue requires a file descriptor for every file in a directory; this would + fail if a file was unreadable by the current user. Now these files are simply + skipped. + +- windows: fix renaming a watched directory if the parent is also watched ([#370]) + +- windows: increase buffer size from 4K to 64K ([#485]) + +- windows: close file handle on Remove() ([#288]) + +- kqueue: put pathname in the error if watching a file fails ([#471]) + +- inotify, windows: calling Close() more than once could race ([#465]) + +- kqueue: improve Close() performance ([#233]) + +- all: various documentation additions and clarifications. + +[#233]: https://github.com/fsnotify/fsnotify/pull/233 +[#260]: https://github.com/fsnotify/fsnotify/pull/260 +[#288]: https://github.com/fsnotify/fsnotify/pull/288 +[#370]: https://github.com/fsnotify/fsnotify/pull/370 +[#434]: https://github.com/fsnotify/fsnotify/pull/434 +[#460]: https://github.com/fsnotify/fsnotify/pull/460 +[#463]: https://github.com/fsnotify/fsnotify/pull/463 +[#465]: https://github.com/fsnotify/fsnotify/pull/465 +[#470]: https://github.com/fsnotify/fsnotify/pull/470 +[#471]: https://github.com/fsnotify/fsnotify/pull/471 +[#475]: https://github.com/fsnotify/fsnotify/pull/475 +[#477]: https://github.com/fsnotify/fsnotify/pull/477 +[#479]: https://github.com/fsnotify/fsnotify/pull/479 +[#480]: https://github.com/fsnotify/fsnotify/pull/480 +[#485]: https://github.com/fsnotify/fsnotify/pull/485 + +## [1.5.4] - 2022-04-25 + +* Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447) +* go.mod: use latest x/sys [#444](https://github.com/fsnotify/fsnotify/pull/444) +* Fix compilation for OpenBSD [#443](https://github.com/fsnotify/fsnotify/pull/443) + +## [1.5.3] - 2022-04-22 + +* This version is retracted. An incorrect branch is published accidentally [#445](https://github.com/fsnotify/fsnotify/issues/445) + +## [1.5.2] - 2022-04-21 + +* Add a feature to return the directories and files that are being monitored [#374](https://github.com/fsnotify/fsnotify/pull/374) +* Fix potential crash on windows if `raw.FileNameLength` exceeds `syscall.MAX_PATH` [#361](https://github.com/fsnotify/fsnotify/pull/361) +* Allow build on unsupported GOOS [#424](https://github.com/fsnotify/fsnotify/pull/424) +* Don't set `poller.fd` twice in `newFdPoller` [#406](https://github.com/fsnotify/fsnotify/pull/406) +* fix go vet warnings: call to `(*T).Fatalf` from a non-test goroutine [#416](https://github.com/fsnotify/fsnotify/pull/416) + +## [1.5.1] - 2021-08-24 + +* Revert Add AddRaw to not follow symlinks [#394](https://github.com/fsnotify/fsnotify/pull/394) + +## [1.5.0] - 2021-08-20 + +* Go: Increase minimum required version to Go 1.12 [#381](https://github.com/fsnotify/fsnotify/pull/381) +* Feature: Add AddRaw method which does not follow symlinks when adding a watch [#289](https://github.com/fsnotify/fsnotify/pull/298) +* Windows: Follow symlinks by default like on all other systems [#289](https://github.com/fsnotify/fsnotify/pull/289) +* CI: Use GitHub Actions for CI and cover go 1.12-1.17 + [#378](https://github.com/fsnotify/fsnotify/pull/378) + [#381](https://github.com/fsnotify/fsnotify/pull/381) + [#385](https://github.com/fsnotify/fsnotify/pull/385) +* Go 1.14+: Fix unsafe pointer conversion [#325](https://github.com/fsnotify/fsnotify/pull/325) + +## [1.4.9] - 2020-03-11 + +* Move example usage to the readme #329. This may resolve #328. + +## [1.4.8] - 2020-03-10 + +* CI: test more go versions (@nathany 1d13583d846ea9d66dcabbfefbfb9d8e6fb05216) +* Tests: Queued inotify events could have been read by the test before max_queued_events was hit (@matthias-stone #265) +* Tests: t.Fatalf -> t.Errorf in go routines (@gdey #266) +* CI: Less verbosity (@nathany #267) +* Tests: Darwin: Exchangedata is deprecated on 10.13 (@nathany #267) +* Tests: Check if channels are closed in the example (@alexeykazakov #244) +* CI: Only run golint on latest version of go and fix issues (@cpuguy83 #284) +* CI: Add windows to travis matrix (@cpuguy83 #284) +* Docs: Remover appveyor badge (@nathany 11844c0959f6fff69ba325d097fce35bd85a8e93) +* Linux: create epoll and pipe fds with close-on-exec (@JohannesEbke #219) +* Linux: open files with close-on-exec (@linxiulei #273) +* Docs: Plan to support fanotify (@nathany ab058b44498e8b7566a799372a39d150d9ea0119 ) +* Project: Add go.mod (@nathany #309) +* Project: Revise editor config (@nathany #309) +* Project: Update copyright for 2019 (@nathany #309) +* CI: Drop go1.8 from CI matrix (@nathany #309) +* Docs: Updating the FAQ section for supportability with NFS & FUSE filesystems (@Pratik32 4bf2d1fec78374803a39307bfb8d340688f4f28e ) + +## [1.4.7] - 2018-01-09 + +* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine) +* Tests: Fix missing verb on format string (thanks @rchiossi) +* Linux: Fix deadlock in Remove (thanks @aarondl) +* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne) +* Docs: Moved FAQ into the README (thanks @vahe) +* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich) +* Docs: replace references to OS X with macOS + +## [1.4.2] - 2016-10-10 + +* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack) + +## [1.4.1] - 2016-10-04 + +* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack) + +## [1.4.0] - 2016-10-01 + +* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie) + +## [1.3.1] - 2016-06-28 + +* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc) + +## [1.3.0] - 2016-04-19 + +* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135) + +## [1.2.10] - 2016-03-02 + +* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj) + +## [1.2.9] - 2016-01-13 + +kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep) + +## [1.2.8] - 2015-12-17 + +* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test) +* inotify: fix race in test +* enable race detection for continuous integration (Linux, Mac, Windows) + +## [1.2.5] - 2015-10-17 + +* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki) +* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken) +* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie) +* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion) + +## [1.2.1] - 2015-10-14 + +* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx) + +## [1.2.0] - 2015-02-08 + +* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD) +* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD) +* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59) + +## [1.1.1] - 2015-02-05 + +* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD) + +## [1.1.0] - 2014-12-12 + +* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43) + * add low-level functions + * only need to store flags on directories + * less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13) + * done can be an unbuffered channel + * remove calls to os.NewSyscallError +* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher) +* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48) +* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) + +## [1.0.4] - 2014-09-07 + +* kqueue: add dragonfly to the build tags. +* Rename source code files, rearrange code so exported APIs are at the top. +* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang) + +## [1.0.3] - 2014-08-19 + +* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36) + +## [1.0.2] - 2014-08-17 + +* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) +* [Fix] Make ./path and path equivalent. (thanks @zhsso) + +## [1.0.0] - 2014-08-15 + +* [API] Remove AddWatch on Windows, use Add. +* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30) +* Minor updates based on feedback from golint. + +## dev / 2014-07-09 + +* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify). +* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno) + +## dev / 2014-07-04 + +* kqueue: fix incorrect mutex used in Close() +* Update example to demonstrate usage of Op. + +## dev / 2014-06-28 + +* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4) +* Fix for String() method on Event (thanks Alex Brainman) +* Don't build on Plan 9 or Solaris (thanks @4ad) + +## dev / 2014-06-21 + +* Events channel of type Event rather than *Event. +* [internal] use syscall constants directly for inotify and kqueue. +* [internal] kqueue: rename events to kevents and fileEvent to event. + +## dev / 2014-06-19 + +* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally). +* [internal] remove cookie from Event struct (unused). +* [internal] Event struct has the same definition across every OS. +* [internal] remove internal watch and removeWatch methods. + +## dev / 2014-06-12 + +* [API] Renamed Watch() to Add() and RemoveWatch() to Remove(). +* [API] Pluralized channel names: Events and Errors. +* [API] Renamed FileEvent struct to Event. +* [API] Op constants replace methods like IsCreate(). + +## dev / 2014-06-12 + +* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) + +## dev / 2014-05-23 + +* [API] Remove current implementation of WatchFlags. + * current implementation doesn't take advantage of OS for efficiency + * provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes + * no tests for the current implementation + * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195) + +## [0.9.3] - 2014-12-31 + +* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) + +## [0.9.2] - 2014-08-17 + +* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) + +## [0.9.1] - 2014-06-12 + +* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) + +## [0.9.0] - 2014-01-17 + +* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany) +* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare) +* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library. + +## [0.8.12] - 2013-11-13 + +* [API] Remove FD_SET and friends from Linux adapter + +## [0.8.11] - 2013-11-02 + +* [Doc] Add Changelog [#72][] (thanks @nathany) +* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond) + +## [0.8.10] - 2013-10-19 + +* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott) +* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer) +* [Doc] specify OS-specific limits in README (thanks @debrando) + +## [0.8.9] - 2013-09-08 + +* [Doc] Contributing (thanks @nathany) +* [Doc] update package path in example code [#63][] (thanks @paulhammond) +* [Doc] GoCI badge in README (Linux only) [#60][] +* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany) + +## [0.8.8] - 2013-06-17 + +* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie) + +## [0.8.7] - 2013-06-03 + +* [API] Make syscall flags internal +* [Fix] inotify: ignore event changes +* [Fix] race in symlink test [#45][] (reported by @srid) +* [Fix] tests on Windows +* lower case error messages + +## [0.8.6] - 2013-05-23 + +* kqueue: Use EVT_ONLY flag on Darwin +* [Doc] Update README with full example + +## [0.8.5] - 2013-05-09 + +* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg) + +## [0.8.4] - 2013-04-07 + +* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz) + +## [0.8.3] - 2013-03-13 + +* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin) +* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin) + +## [0.8.2] - 2013-02-07 + +* [Doc] add Authors +* [Fix] fix data races for map access [#29][] (thanks @fsouza) + +## [0.8.1] - 2013-01-09 + +* [Fix] Windows path separators +* [Doc] BSD License + +## [0.8.0] - 2012-11-09 + +* kqueue: directory watching improvements (thanks @vmirage) +* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto) +* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr) + +## [0.7.4] - 2012-10-09 + +* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji) +* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig) +* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig) +* [Fix] kqueue: modify after recreation of file + +## [0.7.3] - 2012-09-27 + +* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage) +* [Fix] kqueue: no longer get duplicate CREATE events + +## [0.7.2] - 2012-09-01 + +* kqueue: events for created directories + +## [0.7.1] - 2012-07-14 + +* [Fix] for renaming files + +## [0.7.0] - 2012-07-02 + +* [Feature] FSNotify flags +* [Fix] inotify: Added file name back to event path + +## [0.6.0] - 2012-06-06 + +* kqueue: watch files after directory created (thanks @tmc) + +## [0.5.1] - 2012-05-22 + +* [Fix] inotify: remove all watches before Close() + +## [0.5.0] - 2012-05-03 + +* [API] kqueue: return errors during watch instead of sending over channel +* kqueue: match symlink behavior on Linux +* inotify: add `DELETE_SELF` (requested by @taralx) +* [Fix] kqueue: handle EINTR (reported by @robfig) +* [Doc] Godoc example [#1][] (thanks @davecheney) + +## [0.4.0] - 2012-03-30 + +* Go 1 released: build with go tool +* [Feature] Windows support using winfsnotify +* Windows does not have attribute change notifications +* Roll attribute notifications into IsModify + +## [0.3.0] - 2012-02-19 + +* kqueue: add files when watch directory + +## [0.2.0] - 2011-12-30 + +* update to latest Go weekly code + +## [0.1.0] - 2011-10-19 + +* kqueue: add watch on file creation to match inotify +* kqueue: create file event +* inotify: ignore `IN_IGNORED` events +* event String() +* linux: common FileEvent functions +* initial commit + +[#79]: https://github.com/howeyc/fsnotify/pull/79 +[#77]: https://github.com/howeyc/fsnotify/pull/77 +[#72]: https://github.com/howeyc/fsnotify/issues/72 +[#71]: https://github.com/howeyc/fsnotify/issues/71 +[#70]: https://github.com/howeyc/fsnotify/issues/70 +[#63]: https://github.com/howeyc/fsnotify/issues/63 +[#62]: https://github.com/howeyc/fsnotify/issues/62 +[#60]: https://github.com/howeyc/fsnotify/issues/60 +[#59]: https://github.com/howeyc/fsnotify/issues/59 +[#49]: https://github.com/howeyc/fsnotify/issues/49 +[#45]: https://github.com/howeyc/fsnotify/issues/45 +[#40]: https://github.com/howeyc/fsnotify/issues/40 +[#36]: https://github.com/howeyc/fsnotify/issues/36 +[#33]: https://github.com/howeyc/fsnotify/issues/33 +[#29]: https://github.com/howeyc/fsnotify/issues/29 +[#25]: https://github.com/howeyc/fsnotify/issues/25 +[#24]: https://github.com/howeyc/fsnotify/issues/24 +[#21]: https://github.com/howeyc/fsnotify/issues/21 diff --git a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md new file mode 100644 index 00000000..ea379759 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md @@ -0,0 +1,26 @@ +Thank you for your interest in contributing to fsnotify! We try to review and +merge PRs in a reasonable timeframe, but please be aware that: + +- To avoid "wasted" work, please discus changes on the issue tracker first. You + can just send PRs, but they may end up being rejected for one reason or the + other. + +- fsnotify is a cross-platform library, and changes must work reasonably well on + all supported platforms. + +- Changes will need to be compatible; old code should still compile, and the + runtime behaviour can't change in ways that are likely to lead to problems for + users. + +Testing +------- +Just `go test ./...` runs all the tests; the CI runs this on all supported +platforms. Testing different platforms locally can be done with something like +[goon] or [Vagrant], but this isn't super-easy to set up at the moment. + +Use the `-short` flag to make the "stress test" run faster. + + +[goon]: https://github.com/arp242/goon +[Vagrant]: https://www.vagrantup.com/ +[integration_test.go]: /integration_test.go diff --git a/vendor/github.com/fsnotify/fsnotify/LICENSE b/vendor/github.com/fsnotify/fsnotify/LICENSE new file mode 100644 index 00000000..fb03ade7 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/LICENSE @@ -0,0 +1,25 @@ +Copyright © 2012 The Go Authors. All rights reserved. +Copyright © fsnotify 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. diff --git a/vendor/github.com/fsnotify/fsnotify/README.md b/vendor/github.com/fsnotify/fsnotify/README.md new file mode 100644 index 00000000..e480733d --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/README.md @@ -0,0 +1,184 @@ +fsnotify is a Go library to provide cross-platform filesystem notifications on +Windows, Linux, macOS, BSD, and illumos. + +Go 1.17 or newer is required; the full documentation is at +https://pkg.go.dev/github.com/fsnotify/fsnotify + +--- + +Platform support: + +| Backend | OS | Status | +| :-------------------- | :--------- | :------------------------------------------------------------------------ | +| inotify | Linux | Supported | +| kqueue | BSD, macOS | Supported | +| ReadDirectoryChangesW | Windows | Supported | +| FEN | illumos | Supported | +| fanotify | Linux 5.9+ | [Not yet](https://github.com/fsnotify/fsnotify/issues/114) | +| AHAFS | AIX | [aix branch]; experimental due to lack of maintainer and test environment | +| FSEvents | macOS | [Needs support in x/sys/unix][fsevents] | +| USN Journals | Windows | [Needs support in x/sys/windows][usn] | +| Polling | *All* | [Not yet](https://github.com/fsnotify/fsnotify/issues/9) | + +Linux and illumos should include Android and Solaris, but these are currently +untested. + +[fsevents]: https://github.com/fsnotify/fsnotify/issues/11#issuecomment-1279133120 +[usn]: https://github.com/fsnotify/fsnotify/issues/53#issuecomment-1279829847 +[aix branch]: https://github.com/fsnotify/fsnotify/issues/353#issuecomment-1284590129 + +Usage +----- +A basic example: + +```go +package main + +import ( + "log" + + "github.com/fsnotify/fsnotify" +) + +func main() { + // Create new watcher. + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Fatal(err) + } + defer watcher.Close() + + // Start listening for events. + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + log.Println("event:", event) + if event.Has(fsnotify.Write) { + log.Println("modified file:", event.Name) + } + case err, ok := <-watcher.Errors: + if !ok { + return + } + log.Println("error:", err) + } + } + }() + + // Add a path. + err = watcher.Add("/tmp") + if err != nil { + log.Fatal(err) + } + + // Block main goroutine forever. + <-make(chan struct{}) +} +``` + +Some more examples can be found in [cmd/fsnotify](cmd/fsnotify), which can be +run with: + + % go run ./cmd/fsnotify + +Further detailed documentation can be found in godoc: +https://pkg.go.dev/github.com/fsnotify/fsnotify + +FAQ +--- +### Will a file still be watched when it's moved to another directory? +No, not unless you are watching the location it was moved to. + +### Are subdirectories watched? +No, you must add watches for any directory you want to watch (a recursive +watcher is on the roadmap: [#18]). + +[#18]: https://github.com/fsnotify/fsnotify/issues/18 + +### Do I have to watch the Error and Event channels in a goroutine? +Yes. You can read both channels in the same goroutine using `select` (you don't +need a separate goroutine for both channels; see the example). + +### Why don't notifications work with NFS, SMB, FUSE, /proc, or /sys? +fsnotify requires support from underlying OS to work. The current NFS and SMB +protocols does not provide network level support for file notifications, and +neither do the /proc and /sys virtual filesystems. + +This could be fixed with a polling watcher ([#9]), but it's not yet implemented. + +[#9]: https://github.com/fsnotify/fsnotify/issues/9 + +### Why do I get many Chmod events? +Some programs may generate a lot of attribute changes; for example Spotlight on +macOS, anti-virus programs, backup applications, and some others are known to do +this. As a rule, it's typically best to ignore Chmod events. They're often not +useful, and tend to cause problems. + +Spotlight indexing on macOS can result in multiple events (see [#15]). A +temporary workaround is to add your folder(s) to the *Spotlight Privacy +settings* until we have a native FSEvents implementation (see [#11]). + +[#11]: https://github.com/fsnotify/fsnotify/issues/11 +[#15]: https://github.com/fsnotify/fsnotify/issues/15 + +### Watching a file doesn't work well +Watching individual files (rather than directories) is generally not recommended +as many programs (especially editors) update files atomically: it will write to +a temporary file which is then moved to to destination, overwriting the original +(or some variant thereof). The watcher on the original file is now lost, as that +no longer exists. + +The upshot of this is that a power failure or crash won't leave a half-written +file. + +Watch the parent directory and use `Event.Name` to filter out files you're not +interested in. There is an example of this in `cmd/fsnotify/file.go`. + +Platform-specific notes +----------------------- +### Linux +When a file is removed a REMOVE event won't be emitted until all file +descriptors are closed; it will emit a CHMOD instead: + + fp := os.Open("file") + os.Remove("file") // CHMOD + fp.Close() // REMOVE + +This is the event that inotify sends, so not much can be changed about this. + +The `fs.inotify.max_user_watches` sysctl variable specifies the upper limit for +the number of watches per user, and `fs.inotify.max_user_instances` specifies +the maximum number of inotify instances per user. Every Watcher you create is an +"instance", and every path you add is a "watch". + +These are also exposed in `/proc` as `/proc/sys/fs/inotify/max_user_watches` and +`/proc/sys/fs/inotify/max_user_instances` + +To increase them you can use `sysctl` or write the value to proc file: + + # The default values on Linux 5.18 + sysctl fs.inotify.max_user_watches=124983 + sysctl fs.inotify.max_user_instances=128 + +To make the changes persist on reboot edit `/etc/sysctl.conf` or +`/usr/lib/sysctl.d/50-default.conf` (details differ per Linux distro; check your +distro's documentation): + + fs.inotify.max_user_watches=124983 + fs.inotify.max_user_instances=128 + +Reaching the limit will result in a "no space left on device" or "too many open +files" error. + +### kqueue (macOS, all BSD systems) +kqueue requires opening a file descriptor for every file that's being watched; +so if you're watching a directory with five files then that's six file +descriptors. You will run in to your system's "max open files" limit faster on +these platforms. + +The sysctl variables `kern.maxfiles` and `kern.maxfilesperproc` can be used to +control the maximum number of open files. diff --git a/vendor/github.com/fsnotify/fsnotify/backend_fen.go b/vendor/github.com/fsnotify/fsnotify/backend_fen.go new file mode 100644 index 00000000..28497f1d --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_fen.go @@ -0,0 +1,640 @@ +//go:build solaris +// +build solaris + +// Note: the documentation on the Watcher type and methods is generated from +// mkdoc.zsh + +package fsnotify + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "sync" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # Windows notes +// +// Paths can be added as "C:\path\to\dir", but forward slashes +// ("C:/path/to/dir") will also work. +// +// When a watched directory is removed it will always send an event for the +// directory itself, but may not send events for all files in that directory. +// Sometimes it will send events for all times, sometimes it will send no +// events, and often only for some files. +// +// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest +// value that is guaranteed to work with SMB filesystems. If you have many +// events in quick succession this may not be enough, and you will have to use +// [WithBufferSize] to increase the value. +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, and you may + // want to wait until you've stopped receiving them + // (see the dedup example in cmd/fsnotify). + // + // Some systems may send Write event for directories + // when the directory content changes. + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // when a file is truncated. On Windows it's never + // sent. + Events chan Event + + // Errors sends any errors. + // + // ErrEventOverflow is used to indicate there are too many events: + // + // - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl) + // - windows: The buffer size is too small; WithBufferSize() can be used to increase it. + // - kqueue, fen: Not used. + Errors chan error + + mu sync.Mutex + port *unix.EventPort + done chan struct{} // Channel for sending a "quit message" to the reader goroutine + dirs map[string]struct{} // Explicitly watched directories + watches map[string]struct{} // Explicitly watched non-directories +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + return NewBufferedWatcher(0) +} + +// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events +// channel. +// +// The main use case for this is situations with a very large number of events +// where the kernel buffer size can't be increased (e.g. due to lack of +// permissions). An unbuffered Watcher will perform better for almost all use +// cases, and whenever possible you will be better off increasing the kernel +// buffers instead of adding a large userspace buffer. +func NewBufferedWatcher(sz uint) (*Watcher, error) { + w := &Watcher{ + Events: make(chan Event, sz), + Errors: make(chan error), + dirs: make(map[string]struct{}), + watches: make(map[string]struct{}), + done: make(chan struct{}), + } + + var err error + w.port, err = unix.NewEventPort() + if err != nil { + return nil, fmt.Errorf("fsnotify.NewWatcher: %w", err) + } + + go w.readEvents() + return w, nil +} + +// sendEvent attempts to send an event to the user, returning true if the event +// was put in the channel successfully and false if the watcher has been closed. +func (w *Watcher) sendEvent(name string, op Op) (sent bool) { + select { + case w.Events <- Event{Name: name, Op: op}: + return true + case <-w.done: + return false + } +} + +// sendError attempts to send an error to the user, returning true if the error +// was put in the channel successfully and false if the watcher has been closed. +func (w *Watcher) sendError(err error) (sent bool) { + select { + case w.Errors <- err: + return true + case <-w.done: + return false + } +} + +func (w *Watcher) isClosed() bool { + select { + case <-w.done: + return true + default: + return false + } +} + +// Close removes all watches and closes the Events channel. +func (w *Watcher) Close() error { + // Take the lock used by associateFile to prevent lingering events from + // being processed after the close + w.mu.Lock() + defer w.mu.Unlock() + if w.isClosed() { + return nil + } + close(w.done) + return w.port.Close() +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; watching it more than once is a no-op and will +// not return an error. Paths that do not yet exist on the filesystem cannot be +// watched. +// +// A watch will be automatically removed if the watched path is deleted or +// renamed. The exception is the Windows backend, which doesn't remove the +// watcher on renames. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// Returns [ErrClosed] if [Watcher.Close] was called. +// +// See [Watcher.AddWith] for a version that allows adding options. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many programs (especially editors) update files atomically: it +// will write to a temporary file which is then moved to to destination, +// overwriting the original (or some variant thereof). The watcher on the +// original file is now lost, as that no longer exists. +// +// The upshot of this is that a power failure or crash won't leave a +// half-written file. +// +// Watch the parent directory and use Event.Name to filter out files you're not +// interested in. There is an example of this in cmd/fsnotify/file.go. +func (w *Watcher) Add(name string) error { return w.AddWith(name) } + +// AddWith is like [Watcher.Add], but allows adding options. When using Add() +// the defaults described below are used. +// +// Possible options are: +// +// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on +// other platforms. The default is 64K (65536 bytes). +func (w *Watcher) AddWith(name string, opts ...addOpt) error { + if w.isClosed() { + return ErrClosed + } + if w.port.PathIsWatched(name) { + return nil + } + + _ = getOptions(opts...) + + // Currently we resolve symlinks that were explicitly requested to be + // watched. Otherwise we would use LStat here. + stat, err := os.Stat(name) + if err != nil { + return err + } + + // Associate all files in the directory. + if stat.IsDir() { + err := w.handleDirectory(name, stat, true, w.associateFile) + if err != nil { + return err + } + + w.mu.Lock() + w.dirs[name] = struct{}{} + w.mu.Unlock() + return nil + } + + err = w.associateFile(name, stat, true) + if err != nil { + return err + } + + w.mu.Lock() + w.watches[name] = struct{}{} + w.mu.Unlock() + return nil +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +// +// Returns nil if [Watcher.Close] was called. +func (w *Watcher) Remove(name string) error { + if w.isClosed() { + return nil + } + if !w.port.PathIsWatched(name) { + return fmt.Errorf("%w: %s", ErrNonExistentWatch, name) + } + + // The user has expressed an intent. Immediately remove this name from + // whichever watch list it might be in. If it's not in there the delete + // doesn't cause harm. + w.mu.Lock() + delete(w.watches, name) + delete(w.dirs, name) + w.mu.Unlock() + + stat, err := os.Stat(name) + if err != nil { + return err + } + + // Remove associations for every file in the directory. + if stat.IsDir() { + err := w.handleDirectory(name, stat, false, w.dissociateFile) + if err != nil { + return err + } + return nil + } + + err = w.port.DissociatePath(name) + if err != nil { + return err + } + + return nil +} + +// readEvents contains the main loop that runs in a goroutine watching for events. +func (w *Watcher) readEvents() { + // If this function returns, the watcher has been closed and we can close + // these channels + defer func() { + close(w.Errors) + close(w.Events) + }() + + pevents := make([]unix.PortEvent, 8) + for { + count, err := w.port.Get(pevents, 1, nil) + if err != nil && err != unix.ETIME { + // Interrupted system call (count should be 0) ignore and continue + if errors.Is(err, unix.EINTR) && count == 0 { + continue + } + // Get failed because we called w.Close() + if errors.Is(err, unix.EBADF) && w.isClosed() { + return + } + // There was an error not caused by calling w.Close() + if !w.sendError(err) { + return + } + } + + p := pevents[:count] + for _, pevent := range p { + if pevent.Source != unix.PORT_SOURCE_FILE { + // Event from unexpected source received; should never happen. + if !w.sendError(errors.New("Event from unexpected source received")) { + return + } + continue + } + + err = w.handleEvent(&pevent) + if err != nil { + if !w.sendError(err) { + return + } + } + } + } +} + +func (w *Watcher) handleDirectory(path string, stat os.FileInfo, follow bool, handler func(string, os.FileInfo, bool) error) error { + files, err := os.ReadDir(path) + if err != nil { + return err + } + + // Handle all children of the directory. + for _, entry := range files { + finfo, err := entry.Info() + if err != nil { + return err + } + err = handler(filepath.Join(path, finfo.Name()), finfo, false) + if err != nil { + return err + } + } + + // And finally handle the directory itself. + return handler(path, stat, follow) +} + +// handleEvent might need to emit more than one fsnotify event if the events +// bitmap matches more than one event type (e.g. the file was both modified and +// had the attributes changed between when the association was created and the +// when event was returned) +func (w *Watcher) handleEvent(event *unix.PortEvent) error { + var ( + events = event.Events + path = event.Path + fmode = event.Cookie.(os.FileMode) + reRegister = true + ) + + w.mu.Lock() + _, watchedDir := w.dirs[path] + _, watchedPath := w.watches[path] + w.mu.Unlock() + isWatched := watchedDir || watchedPath + + if events&unix.FILE_DELETE != 0 { + if !w.sendEvent(path, Remove) { + return nil + } + reRegister = false + } + if events&unix.FILE_RENAME_FROM != 0 { + if !w.sendEvent(path, Rename) { + return nil + } + // Don't keep watching the new file name + reRegister = false + } + if events&unix.FILE_RENAME_TO != 0 { + // We don't report a Rename event for this case, because Rename events + // are interpreted as referring to the _old_ name of the file, and in + // this case the event would refer to the new name of the file. This + // type of rename event is not supported by fsnotify. + + // inotify reports a Remove event in this case, so we simulate this + // here. + if !w.sendEvent(path, Remove) { + return nil + } + // Don't keep watching the file that was removed + reRegister = false + } + + // The file is gone, nothing left to do. + if !reRegister { + if watchedDir { + w.mu.Lock() + delete(w.dirs, path) + w.mu.Unlock() + } + if watchedPath { + w.mu.Lock() + delete(w.watches, path) + w.mu.Unlock() + } + return nil + } + + // If we didn't get a deletion the file still exists and we're going to have + // to watch it again. Let's Stat it now so that we can compare permissions + // and have what we need to continue watching the file + + stat, err := os.Lstat(path) + if err != nil { + // This is unexpected, but we should still emit an event. This happens + // most often on "rm -r" of a subdirectory inside a watched directory We + // get a modify event of something happening inside, but by the time we + // get here, the sudirectory is already gone. Clearly we were watching + // this path but now it is gone. Let's tell the user that it was + // removed. + if !w.sendEvent(path, Remove) { + return nil + } + // Suppress extra write events on removed directories; they are not + // informative and can be confusing. + return nil + } + + // resolve symlinks that were explicitly watched as we would have at Add() + // time. this helps suppress spurious Chmod events on watched symlinks + if isWatched { + stat, err = os.Stat(path) + if err != nil { + // The symlink still exists, but the target is gone. Report the + // Remove similar to above. + if !w.sendEvent(path, Remove) { + return nil + } + // Don't return the error + } + } + + if events&unix.FILE_MODIFIED != 0 { + if fmode.IsDir() { + if watchedDir { + if err := w.updateDirectory(path); err != nil { + return err + } + } else { + if !w.sendEvent(path, Write) { + return nil + } + } + } else { + if !w.sendEvent(path, Write) { + return nil + } + } + } + if events&unix.FILE_ATTRIB != 0 && stat != nil { + // Only send Chmod if perms changed + if stat.Mode().Perm() != fmode.Perm() { + if !w.sendEvent(path, Chmod) { + return nil + } + } + } + + if stat != nil { + // If we get here, it means we've hit an event above that requires us to + // continue watching the file or directory + return w.associateFile(path, stat, isWatched) + } + return nil +} + +func (w *Watcher) updateDirectory(path string) error { + // The directory was modified, so we must find unwatched entities and watch + // them. If something was removed from the directory, nothing will happen, + // as everything else should still be watched. + files, err := os.ReadDir(path) + if err != nil { + return err + } + + for _, entry := range files { + path := filepath.Join(path, entry.Name()) + if w.port.PathIsWatched(path) { + continue + } + + finfo, err := entry.Info() + if err != nil { + return err + } + err = w.associateFile(path, finfo, false) + if err != nil { + if !w.sendError(err) { + return nil + } + } + if !w.sendEvent(path, Create) { + return nil + } + } + return nil +} + +func (w *Watcher) associateFile(path string, stat os.FileInfo, follow bool) error { + if w.isClosed() { + return ErrClosed + } + // This is primarily protecting the call to AssociatePath but it is + // important and intentional that the call to PathIsWatched is also + // protected by this mutex. Without this mutex, AssociatePath has been seen + // to error out that the path is already associated. + w.mu.Lock() + defer w.mu.Unlock() + + if w.port.PathIsWatched(path) { + // Remove the old association in favor of this one If we get ENOENT, + // then while the x/sys/unix wrapper still thought that this path was + // associated, the underlying event port did not. This call will have + // cleared up that discrepancy. The most likely cause is that the event + // has fired but we haven't processed it yet. + err := w.port.DissociatePath(path) + if err != nil && err != unix.ENOENT { + return err + } + } + // FILE_NOFOLLOW means we watch symlinks themselves rather than their + // targets. + events := unix.FILE_MODIFIED | unix.FILE_ATTRIB | unix.FILE_NOFOLLOW + if follow { + // We *DO* follow symlinks for explicitly watched entries. + events = unix.FILE_MODIFIED | unix.FILE_ATTRIB + } + return w.port.AssociatePath(path, stat, + events, + stat.Mode()) +} + +func (w *Watcher) dissociateFile(path string, stat os.FileInfo, unused bool) error { + if !w.port.PathIsWatched(path) { + return nil + } + return w.port.DissociatePath(path) +} + +// WatchList returns all paths explicitly added with [Watcher.Add] (and are not +// yet removed). +// +// Returns nil if [Watcher.Close] was called. +func (w *Watcher) WatchList() []string { + if w.isClosed() { + return nil + } + + w.mu.Lock() + defer w.mu.Unlock() + + entries := make([]string, 0, len(w.watches)+len(w.dirs)) + for pathname := range w.dirs { + entries = append(entries, pathname) + } + for pathname := range w.watches { + entries = append(entries, pathname) + } + + return entries +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_inotify.go b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go new file mode 100644 index 00000000..921c1c1e --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go @@ -0,0 +1,594 @@ +//go:build linux && !appengine +// +build linux,!appengine + +// Note: the documentation on the Watcher type and methods is generated from +// mkdoc.zsh + +package fsnotify + +import ( + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "unsafe" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # Windows notes +// +// Paths can be added as "C:\path\to\dir", but forward slashes +// ("C:/path/to/dir") will also work. +// +// When a watched directory is removed it will always send an event for the +// directory itself, but may not send events for all files in that directory. +// Sometimes it will send events for all times, sometimes it will send no +// events, and often only for some files. +// +// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest +// value that is guaranteed to work with SMB filesystems. If you have many +// events in quick succession this may not be enough, and you will have to use +// [WithBufferSize] to increase the value. +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, and you may + // want to wait until you've stopped receiving them + // (see the dedup example in cmd/fsnotify). + // + // Some systems may send Write event for directories + // when the directory content changes. + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // when a file is truncated. On Windows it's never + // sent. + Events chan Event + + // Errors sends any errors. + // + // ErrEventOverflow is used to indicate there are too many events: + // + // - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl) + // - windows: The buffer size is too small; WithBufferSize() can be used to increase it. + // - kqueue, fen: Not used. + Errors chan error + + // Store fd here as os.File.Read() will no longer return on close after + // calling Fd(). See: https://github.com/golang/go/issues/26439 + fd int + inotifyFile *os.File + watches *watches + done chan struct{} // Channel for sending a "quit message" to the reader goroutine + closeMu sync.Mutex + doneResp chan struct{} // Channel to respond to Close +} + +type ( + watches struct { + mu sync.RWMutex + wd map[uint32]*watch // wd → watch + path map[string]uint32 // pathname → wd + } + watch struct { + wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) + flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) + path string // Watch path. + } +) + +func newWatches() *watches { + return &watches{ + wd: make(map[uint32]*watch), + path: make(map[string]uint32), + } +} + +func (w *watches) len() int { + w.mu.RLock() + defer w.mu.RUnlock() + return len(w.wd) +} + +func (w *watches) add(ww *watch) { + w.mu.Lock() + defer w.mu.Unlock() + w.wd[ww.wd] = ww + w.path[ww.path] = ww.wd +} + +func (w *watches) remove(wd uint32) { + w.mu.Lock() + defer w.mu.Unlock() + delete(w.path, w.wd[wd].path) + delete(w.wd, wd) +} + +func (w *watches) removePath(path string) (uint32, bool) { + w.mu.Lock() + defer w.mu.Unlock() + + wd, ok := w.path[path] + if !ok { + return 0, false + } + + delete(w.path, path) + delete(w.wd, wd) + + return wd, true +} + +func (w *watches) byPath(path string) *watch { + w.mu.RLock() + defer w.mu.RUnlock() + return w.wd[w.path[path]] +} + +func (w *watches) byWd(wd uint32) *watch { + w.mu.RLock() + defer w.mu.RUnlock() + return w.wd[wd] +} + +func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error { + w.mu.Lock() + defer w.mu.Unlock() + + var existing *watch + wd, ok := w.path[path] + if ok { + existing = w.wd[wd] + } + + upd, err := f(existing) + if err != nil { + return err + } + if upd != nil { + w.wd[upd.wd] = upd + w.path[upd.path] = upd.wd + + if upd.wd != wd { + delete(w.wd, wd) + } + } + + return nil +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + return NewBufferedWatcher(0) +} + +// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events +// channel. +// +// The main use case for this is situations with a very large number of events +// where the kernel buffer size can't be increased (e.g. due to lack of +// permissions). An unbuffered Watcher will perform better for almost all use +// cases, and whenever possible you will be better off increasing the kernel +// buffers instead of adding a large userspace buffer. +func NewBufferedWatcher(sz uint) (*Watcher, error) { + // Need to set nonblocking mode for SetDeadline to work, otherwise blocking + // I/O operations won't terminate on close. + fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK) + if fd == -1 { + return nil, errno + } + + w := &Watcher{ + fd: fd, + inotifyFile: os.NewFile(uintptr(fd), ""), + watches: newWatches(), + Events: make(chan Event, sz), + Errors: make(chan error), + done: make(chan struct{}), + doneResp: make(chan struct{}), + } + + go w.readEvents() + return w, nil +} + +// Returns true if the event was sent, or false if watcher is closed. +func (w *Watcher) sendEvent(e Event) bool { + select { + case w.Events <- e: + return true + case <-w.done: + return false + } +} + +// Returns true if the error was sent, or false if watcher is closed. +func (w *Watcher) sendError(err error) bool { + select { + case w.Errors <- err: + return true + case <-w.done: + return false + } +} + +func (w *Watcher) isClosed() bool { + select { + case <-w.done: + return true + default: + return false + } +} + +// Close removes all watches and closes the Events channel. +func (w *Watcher) Close() error { + w.closeMu.Lock() + if w.isClosed() { + w.closeMu.Unlock() + return nil + } + close(w.done) + w.closeMu.Unlock() + + // Causes any blocking reads to return with an error, provided the file + // still supports deadline operations. + err := w.inotifyFile.Close() + if err != nil { + return err + } + + // Wait for goroutine to close + <-w.doneResp + + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; watching it more than once is a no-op and will +// not return an error. Paths that do not yet exist on the filesystem cannot be +// watched. +// +// A watch will be automatically removed if the watched path is deleted or +// renamed. The exception is the Windows backend, which doesn't remove the +// watcher on renames. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// Returns [ErrClosed] if [Watcher.Close] was called. +// +// See [Watcher.AddWith] for a version that allows adding options. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many programs (especially editors) update files atomically: it +// will write to a temporary file which is then moved to to destination, +// overwriting the original (or some variant thereof). The watcher on the +// original file is now lost, as that no longer exists. +// +// The upshot of this is that a power failure or crash won't leave a +// half-written file. +// +// Watch the parent directory and use Event.Name to filter out files you're not +// interested in. There is an example of this in cmd/fsnotify/file.go. +func (w *Watcher) Add(name string) error { return w.AddWith(name) } + +// AddWith is like [Watcher.Add], but allows adding options. When using Add() +// the defaults described below are used. +// +// Possible options are: +// +// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on +// other platforms. The default is 64K (65536 bytes). +func (w *Watcher) AddWith(name string, opts ...addOpt) error { + if w.isClosed() { + return ErrClosed + } + + name = filepath.Clean(name) + _ = getOptions(opts...) + + var flags uint32 = unix.IN_MOVED_TO | unix.IN_MOVED_FROM | + unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY | + unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF + + return w.watches.updatePath(name, func(existing *watch) (*watch, error) { + if existing != nil { + flags |= existing.flags | unix.IN_MASK_ADD + } + + wd, err := unix.InotifyAddWatch(w.fd, name, flags) + if wd == -1 { + return nil, err + } + + if existing == nil { + return &watch{ + wd: uint32(wd), + path: name, + flags: flags, + }, nil + } + + existing.wd = uint32(wd) + existing.flags = flags + return existing, nil + }) +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +// +// Returns nil if [Watcher.Close] was called. +func (w *Watcher) Remove(name string) error { + if w.isClosed() { + return nil + } + return w.remove(filepath.Clean(name)) +} + +func (w *Watcher) remove(name string) error { + wd, ok := w.watches.removePath(name) + if !ok { + return fmt.Errorf("%w: %s", ErrNonExistentWatch, name) + } + + success, errno := unix.InotifyRmWatch(w.fd, wd) + if success == -1 { + // TODO: Perhaps it's not helpful to return an error here in every case; + // The only two possible errors are: + // + // - EBADF, which happens when w.fd is not a valid file descriptor + // of any kind. + // - EINVAL, which is when fd is not an inotify descriptor or wd + // is not a valid watch descriptor. Watch descriptors are + // invalidated when they are removed explicitly or implicitly; + // explicitly by inotify_rm_watch, implicitly when the file they + // are watching is deleted. + return errno + } + return nil +} + +// WatchList returns all paths explicitly added with [Watcher.Add] (and are not +// yet removed). +// +// Returns nil if [Watcher.Close] was called. +func (w *Watcher) WatchList() []string { + if w.isClosed() { + return nil + } + + entries := make([]string, 0, w.watches.len()) + w.watches.mu.RLock() + for pathname := range w.watches.path { + entries = append(entries, pathname) + } + w.watches.mu.RUnlock() + + return entries +} + +// readEvents reads from the inotify file descriptor, converts the +// received events into Event objects and sends them via the Events channel +func (w *Watcher) readEvents() { + defer func() { + close(w.doneResp) + close(w.Errors) + close(w.Events) + }() + + var ( + buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events + errno error // Syscall errno + ) + for { + // See if we have been closed. + if w.isClosed() { + return + } + + n, err := w.inotifyFile.Read(buf[:]) + switch { + case errors.Unwrap(err) == os.ErrClosed: + return + case err != nil: + if !w.sendError(err) { + return + } + continue + } + + if n < unix.SizeofInotifyEvent { + var err error + if n == 0 { + err = io.EOF // If EOF is received. This should really never happen. + } else if n < 0 { + err = errno // If an error occurred while reading. + } else { + err = errors.New("notify: short read in readEvents()") // Read was too short. + } + if !w.sendError(err) { + return + } + continue + } + + var offset uint32 + // We don't know how many events we just read into the buffer + // While the offset points to at least one whole event... + for offset <= uint32(n-unix.SizeofInotifyEvent) { + var ( + // Point "raw" to the event in the buffer + raw = (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) + mask = uint32(raw.Mask) + nameLen = uint32(raw.Len) + ) + + if mask&unix.IN_Q_OVERFLOW != 0 { + if !w.sendError(ErrEventOverflow) { + return + } + } + + // If the event happened to the watched directory or the watched file, the kernel + // doesn't append the filename to the event, but we would like to always fill the + // the "Name" field with a valid filename. We retrieve the path of the watch from + // the "paths" map. + watch := w.watches.byWd(uint32(raw.Wd)) + + // inotify will automatically remove the watch on deletes; just need + // to clean our state here. + if watch != nil && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF { + w.watches.remove(watch.wd) + } + // We can't really update the state when a watched path is moved; + // only IN_MOVE_SELF is sent and not IN_MOVED_{FROM,TO}. So remove + // the watch. + if watch != nil && mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF { + err := w.remove(watch.path) + if err != nil && !errors.Is(err, ErrNonExistentWatch) { + if !w.sendError(err) { + return + } + } + } + + var name string + if watch != nil { + name = watch.path + } + if nameLen > 0 { + // Point "bytes" at the first byte of the filename + bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen] + // The filename is padded with NULL bytes. TrimRight() gets rid of those. + name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") + } + + event := w.newEvent(name, mask) + + // Send the events that are not ignored on the events channel + if mask&unix.IN_IGNORED == 0 { + if !w.sendEvent(event) { + return + } + } + + // Move to the next event in the buffer + offset += unix.SizeofInotifyEvent + nameLen + } + } +} + +// newEvent returns an platform-independent Event based on an inotify mask. +func (w *Watcher) newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO { + e.Op |= Create + } + if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE { + e.Op |= Remove + } + if mask&unix.IN_MODIFY == unix.IN_MODIFY { + e.Op |= Write + } + if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM { + e.Op |= Rename + } + if mask&unix.IN_ATTRIB == unix.IN_ATTRIB { + e.Op |= Chmod + } + return e +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go new file mode 100644 index 00000000..063a0915 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go @@ -0,0 +1,782 @@ +//go:build freebsd || openbsd || netbsd || dragonfly || darwin +// +build freebsd openbsd netbsd dragonfly darwin + +// Note: the documentation on the Watcher type and methods is generated from +// mkdoc.zsh + +package fsnotify + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "sync" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # Windows notes +// +// Paths can be added as "C:\path\to\dir", but forward slashes +// ("C:/path/to/dir") will also work. +// +// When a watched directory is removed it will always send an event for the +// directory itself, but may not send events for all files in that directory. +// Sometimes it will send events for all times, sometimes it will send no +// events, and often only for some files. +// +// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest +// value that is guaranteed to work with SMB filesystems. If you have many +// events in quick succession this may not be enough, and you will have to use +// [WithBufferSize] to increase the value. +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, and you may + // want to wait until you've stopped receiving them + // (see the dedup example in cmd/fsnotify). + // + // Some systems may send Write event for directories + // when the directory content changes. + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // when a file is truncated. On Windows it's never + // sent. + Events chan Event + + // Errors sends any errors. + // + // ErrEventOverflow is used to indicate there are too many events: + // + // - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl) + // - windows: The buffer size is too small; WithBufferSize() can be used to increase it. + // - kqueue, fen: Not used. + Errors chan error + + done chan struct{} + kq int // File descriptor (as returned by the kqueue() syscall). + closepipe [2]int // Pipe used for closing. + mu sync.Mutex // Protects access to watcher data + watches map[string]int // Watched file descriptors (key: path). + watchesByDir map[string]map[int]struct{} // Watched file descriptors indexed by the parent directory (key: dirname(path)). + userWatches map[string]struct{} // Watches added with Watcher.Add() + dirFlags map[string]uint32 // Watched directories to fflags used in kqueue. + paths map[int]pathInfo // File descriptors to path names for processing kqueue events. + fileExists map[string]struct{} // Keep track of if we know this file exists (to stop duplicate create events). + isClosed bool // Set to true when Close() is first called +} + +type pathInfo struct { + name string + isDir bool +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + return NewBufferedWatcher(0) +} + +// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events +// channel. +// +// The main use case for this is situations with a very large number of events +// where the kernel buffer size can't be increased (e.g. due to lack of +// permissions). An unbuffered Watcher will perform better for almost all use +// cases, and whenever possible you will be better off increasing the kernel +// buffers instead of adding a large userspace buffer. +func NewBufferedWatcher(sz uint) (*Watcher, error) { + kq, closepipe, err := newKqueue() + if err != nil { + return nil, err + } + + w := &Watcher{ + kq: kq, + closepipe: closepipe, + watches: make(map[string]int), + watchesByDir: make(map[string]map[int]struct{}), + dirFlags: make(map[string]uint32), + paths: make(map[int]pathInfo), + fileExists: make(map[string]struct{}), + userWatches: make(map[string]struct{}), + Events: make(chan Event, sz), + Errors: make(chan error), + done: make(chan struct{}), + } + + go w.readEvents() + return w, nil +} + +// newKqueue creates a new kernel event queue and returns a descriptor. +// +// This registers a new event on closepipe, which will trigger an event when +// it's closed. This way we can use kevent() without timeout/polling; without +// the closepipe, it would block forever and we wouldn't be able to stop it at +// all. +func newKqueue() (kq int, closepipe [2]int, err error) { + kq, err = unix.Kqueue() + if kq == -1 { + return kq, closepipe, err + } + + // Register the close pipe. + err = unix.Pipe(closepipe[:]) + if err != nil { + unix.Close(kq) + return kq, closepipe, err + } + + // Register changes to listen on the closepipe. + changes := make([]unix.Kevent_t, 1) + // SetKevent converts int to the platform-specific types. + unix.SetKevent(&changes[0], closepipe[0], unix.EVFILT_READ, + unix.EV_ADD|unix.EV_ENABLE|unix.EV_ONESHOT) + + ok, err := unix.Kevent(kq, changes, nil, nil) + if ok == -1 { + unix.Close(kq) + unix.Close(closepipe[0]) + unix.Close(closepipe[1]) + return kq, closepipe, err + } + return kq, closepipe, nil +} + +// Returns true if the event was sent, or false if watcher is closed. +func (w *Watcher) sendEvent(e Event) bool { + select { + case w.Events <- e: + return true + case <-w.done: + return false + } +} + +// Returns true if the error was sent, or false if watcher is closed. +func (w *Watcher) sendError(err error) bool { + select { + case w.Errors <- err: + return true + case <-w.done: + return false + } +} + +// Close removes all watches and closes the Events channel. +func (w *Watcher) Close() error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return nil + } + w.isClosed = true + + // copy paths to remove while locked + pathsToRemove := make([]string, 0, len(w.watches)) + for name := range w.watches { + pathsToRemove = append(pathsToRemove, name) + } + w.mu.Unlock() // Unlock before calling Remove, which also locks + for _, name := range pathsToRemove { + w.Remove(name) + } + + // Send "quit" message to the reader goroutine. + unix.Close(w.closepipe[1]) + close(w.done) + + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; watching it more than once is a no-op and will +// not return an error. Paths that do not yet exist on the filesystem cannot be +// watched. +// +// A watch will be automatically removed if the watched path is deleted or +// renamed. The exception is the Windows backend, which doesn't remove the +// watcher on renames. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// Returns [ErrClosed] if [Watcher.Close] was called. +// +// See [Watcher.AddWith] for a version that allows adding options. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many programs (especially editors) update files atomically: it +// will write to a temporary file which is then moved to to destination, +// overwriting the original (or some variant thereof). The watcher on the +// original file is now lost, as that no longer exists. +// +// The upshot of this is that a power failure or crash won't leave a +// half-written file. +// +// Watch the parent directory and use Event.Name to filter out files you're not +// interested in. There is an example of this in cmd/fsnotify/file.go. +func (w *Watcher) Add(name string) error { return w.AddWith(name) } + +// AddWith is like [Watcher.Add], but allows adding options. When using Add() +// the defaults described below are used. +// +// Possible options are: +// +// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on +// other platforms. The default is 64K (65536 bytes). +func (w *Watcher) AddWith(name string, opts ...addOpt) error { + _ = getOptions(opts...) + + w.mu.Lock() + w.userWatches[name] = struct{}{} + w.mu.Unlock() + _, err := w.addWatch(name, noteAllEvents) + return err +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +// +// Returns nil if [Watcher.Close] was called. +func (w *Watcher) Remove(name string) error { + return w.remove(name, true) +} + +func (w *Watcher) remove(name string, unwatchFiles bool) error { + name = filepath.Clean(name) + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return nil + } + watchfd, ok := w.watches[name] + w.mu.Unlock() + if !ok { + return fmt.Errorf("%w: %s", ErrNonExistentWatch, name) + } + + err := w.register([]int{watchfd}, unix.EV_DELETE, 0) + if err != nil { + return err + } + + unix.Close(watchfd) + + w.mu.Lock() + isDir := w.paths[watchfd].isDir + delete(w.watches, name) + delete(w.userWatches, name) + + parentName := filepath.Dir(name) + delete(w.watchesByDir[parentName], watchfd) + + if len(w.watchesByDir[parentName]) == 0 { + delete(w.watchesByDir, parentName) + } + + delete(w.paths, watchfd) + delete(w.dirFlags, name) + delete(w.fileExists, name) + w.mu.Unlock() + + // Find all watched paths that are in this directory that are not external. + if unwatchFiles && isDir { + var pathsToRemove []string + w.mu.Lock() + for fd := range w.watchesByDir[name] { + path := w.paths[fd] + if _, ok := w.userWatches[path.name]; !ok { + pathsToRemove = append(pathsToRemove, path.name) + } + } + w.mu.Unlock() + for _, name := range pathsToRemove { + // Since these are internal, not much sense in propagating error to + // the user, as that will just confuse them with an error about a + // path they did not explicitly watch themselves. + w.Remove(name) + } + } + return nil +} + +// WatchList returns all paths explicitly added with [Watcher.Add] (and are not +// yet removed). +// +// Returns nil if [Watcher.Close] was called. +func (w *Watcher) WatchList() []string { + w.mu.Lock() + defer w.mu.Unlock() + if w.isClosed { + return nil + } + + entries := make([]string, 0, len(w.userWatches)) + for pathname := range w.userWatches { + entries = append(entries, pathname) + } + + return entries +} + +// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE) +const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME + +// addWatch adds name to the watched file set; the flags are interpreted as +// described in kevent(2). +// +// Returns the real path to the file which was added, with symlinks resolved. +func (w *Watcher) addWatch(name string, flags uint32) (string, error) { + var isDir bool + name = filepath.Clean(name) + + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return "", ErrClosed + } + watchfd, alreadyWatching := w.watches[name] + // We already have a watch, but we can still override flags. + if alreadyWatching { + isDir = w.paths[watchfd].isDir + } + w.mu.Unlock() + + if !alreadyWatching { + fi, err := os.Lstat(name) + if err != nil { + return "", err + } + + // Don't watch sockets or named pipes + if (fi.Mode()&os.ModeSocket == os.ModeSocket) || (fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe) { + return "", nil + } + + // Follow Symlinks. + if fi.Mode()&os.ModeSymlink == os.ModeSymlink { + link, err := os.Readlink(name) + if err != nil { + // Return nil because Linux can add unresolvable symlinks to the + // watch list without problems, so maintain consistency with + // that. There will be no file events for broken symlinks. + // TODO: more specific check; returns os.PathError; ENOENT? + return "", nil + } + + w.mu.Lock() + _, alreadyWatching = w.watches[link] + w.mu.Unlock() + + if alreadyWatching { + // Add to watches so we don't get spurious Create events later + // on when we diff the directories. + w.watches[name] = 0 + w.fileExists[name] = struct{}{} + return link, nil + } + + name = link + fi, err = os.Lstat(name) + if err != nil { + return "", nil + } + } + + // Retry on EINTR; open() can return EINTR in practice on macOS. + // See #354, and Go issues 11180 and 39237. + for { + watchfd, err = unix.Open(name, openMode, 0) + if err == nil { + break + } + if errors.Is(err, unix.EINTR) { + continue + } + + return "", err + } + + isDir = fi.IsDir() + } + + err := w.register([]int{watchfd}, unix.EV_ADD|unix.EV_CLEAR|unix.EV_ENABLE, flags) + if err != nil { + unix.Close(watchfd) + return "", err + } + + if !alreadyWatching { + w.mu.Lock() + parentName := filepath.Dir(name) + w.watches[name] = watchfd + + watchesByDir, ok := w.watchesByDir[parentName] + if !ok { + watchesByDir = make(map[int]struct{}, 1) + w.watchesByDir[parentName] = watchesByDir + } + watchesByDir[watchfd] = struct{}{} + w.paths[watchfd] = pathInfo{name: name, isDir: isDir} + w.mu.Unlock() + } + + if isDir { + // Watch the directory if it has not been watched before, or if it was + // watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles) + w.mu.Lock() + + watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && + (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE) + // Store flags so this watch can be updated later + w.dirFlags[name] = flags + w.mu.Unlock() + + if watchDir { + if err := w.watchDirectoryFiles(name); err != nil { + return "", err + } + } + } + return name, nil +} + +// readEvents reads from kqueue and converts the received kevents into +// Event values that it sends down the Events channel. +func (w *Watcher) readEvents() { + defer func() { + close(w.Events) + close(w.Errors) + _ = unix.Close(w.kq) + unix.Close(w.closepipe[0]) + }() + + eventBuffer := make([]unix.Kevent_t, 10) + for closed := false; !closed; { + kevents, err := w.read(eventBuffer) + // EINTR is okay, the syscall was interrupted before timeout expired. + if err != nil && err != unix.EINTR { + if !w.sendError(fmt.Errorf("fsnotify.readEvents: %w", err)) { + closed = true + } + continue + } + + // Flush the events we received to the Events channel + for _, kevent := range kevents { + var ( + watchfd = int(kevent.Ident) + mask = uint32(kevent.Fflags) + ) + + // Shut down the loop when the pipe is closed, but only after all + // other events have been processed. + if watchfd == w.closepipe[0] { + closed = true + continue + } + + w.mu.Lock() + path := w.paths[watchfd] + w.mu.Unlock() + + event := w.newEvent(path.name, mask) + + if event.Has(Rename) || event.Has(Remove) { + w.remove(event.Name, false) + w.mu.Lock() + delete(w.fileExists, event.Name) + w.mu.Unlock() + } + + if path.isDir && event.Has(Write) && !event.Has(Remove) { + w.sendDirectoryChangeEvents(event.Name) + } else { + if !w.sendEvent(event) { + closed = true + continue + } + } + + if event.Has(Remove) { + // Look for a file that may have overwritten this; for example, + // mv f1 f2 will delete f2, then create f2. + if path.isDir { + fileDir := filepath.Clean(event.Name) + w.mu.Lock() + _, found := w.watches[fileDir] + w.mu.Unlock() + if found { + err := w.sendDirectoryChangeEvents(fileDir) + if err != nil { + if !w.sendError(err) { + closed = true + } + } + } + } else { + filePath := filepath.Clean(event.Name) + if fi, err := os.Lstat(filePath); err == nil { + err := w.sendFileCreatedEventIfNew(filePath, fi) + if err != nil { + if !w.sendError(err) { + closed = true + } + } + } + } + } + } + } +} + +// newEvent returns an platform-independent Event based on kqueue Fflags. +func (w *Watcher) newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&unix.NOTE_DELETE == unix.NOTE_DELETE { + e.Op |= Remove + } + if mask&unix.NOTE_WRITE == unix.NOTE_WRITE { + e.Op |= Write + } + if mask&unix.NOTE_RENAME == unix.NOTE_RENAME { + e.Op |= Rename + } + if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB { + e.Op |= Chmod + } + // No point sending a write and delete event at the same time: if it's gone, + // then it's gone. + if e.Op.Has(Write) && e.Op.Has(Remove) { + e.Op &^= Write + } + return e +} + +// watchDirectoryFiles to mimic inotify when adding a watch on a directory +func (w *Watcher) watchDirectoryFiles(dirPath string) error { + // Get all files + files, err := os.ReadDir(dirPath) + if err != nil { + return err + } + + for _, f := range files { + path := filepath.Join(dirPath, f.Name()) + + fi, err := f.Info() + if err != nil { + return fmt.Errorf("%q: %w", path, err) + } + + cleanPath, err := w.internalWatch(path, fi) + if err != nil { + // No permission to read the file; that's not a problem: just skip. + // But do add it to w.fileExists to prevent it from being picked up + // as a "new" file later (it still shows up in the directory + // listing). + switch { + case errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM): + cleanPath = filepath.Clean(path) + default: + return fmt.Errorf("%q: %w", path, err) + } + } + + w.mu.Lock() + w.fileExists[cleanPath] = struct{}{} + w.mu.Unlock() + } + + return nil +} + +// Search the directory for new files and send an event for them. +// +// This functionality is to have the BSD watcher match the inotify, which sends +// a create event for files created in a watched directory. +func (w *Watcher) sendDirectoryChangeEvents(dir string) error { + files, err := os.ReadDir(dir) + if err != nil { + // Directory no longer exists: we can ignore this safely. kqueue will + // still give us the correct events. + if errors.Is(err, os.ErrNotExist) { + return nil + } + return fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err) + } + + for _, f := range files { + fi, err := f.Info() + if err != nil { + return fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err) + } + + err = w.sendFileCreatedEventIfNew(filepath.Join(dir, fi.Name()), fi) + if err != nil { + // Don't need to send an error if this file isn't readable. + if errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM) { + return nil + } + return fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err) + } + } + return nil +} + +// sendFileCreatedEvent sends a create event if the file isn't already being tracked. +func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fi os.FileInfo) (err error) { + w.mu.Lock() + _, doesExist := w.fileExists[filePath] + w.mu.Unlock() + if !doesExist { + if !w.sendEvent(Event{Name: filePath, Op: Create}) { + return + } + } + + // like watchDirectoryFiles (but without doing another ReadDir) + filePath, err = w.internalWatch(filePath, fi) + if err != nil { + return err + } + + w.mu.Lock() + w.fileExists[filePath] = struct{}{} + w.mu.Unlock() + + return nil +} + +func (w *Watcher) internalWatch(name string, fi os.FileInfo) (string, error) { + if fi.IsDir() { + // mimic Linux providing delete events for subdirectories, but preserve + // the flags used if currently watching subdirectory + w.mu.Lock() + flags := w.dirFlags[name] + w.mu.Unlock() + + flags |= unix.NOTE_DELETE | unix.NOTE_RENAME + return w.addWatch(name, flags) + } + + // watch file to mimic Linux inotify + return w.addWatch(name, noteAllEvents) +} + +// Register events with the queue. +func (w *Watcher) register(fds []int, flags int, fflags uint32) error { + changes := make([]unix.Kevent_t, len(fds)) + for i, fd := range fds { + // SetKevent converts int to the platform-specific types. + unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags) + changes[i].Fflags = fflags + } + + // Register the events. + success, err := unix.Kevent(w.kq, changes, nil, nil) + if success == -1 { + return err + } + return nil +} + +// read retrieves pending events, or waits until an event occurs. +func (w *Watcher) read(events []unix.Kevent_t) ([]unix.Kevent_t, error) { + n, err := unix.Kevent(w.kq, nil, events, nil) + if err != nil { + return nil, err + } + return events[0:n], nil +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_other.go b/vendor/github.com/fsnotify/fsnotify/backend_other.go new file mode 100644 index 00000000..d34a23c0 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_other.go @@ -0,0 +1,205 @@ +//go:build appengine || (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows) +// +build appengine !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows + +// Note: the documentation on the Watcher type and methods is generated from +// mkdoc.zsh + +package fsnotify + +import "errors" + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # Windows notes +// +// Paths can be added as "C:\path\to\dir", but forward slashes +// ("C:/path/to/dir") will also work. +// +// When a watched directory is removed it will always send an event for the +// directory itself, but may not send events for all files in that directory. +// Sometimes it will send events for all times, sometimes it will send no +// events, and often only for some files. +// +// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest +// value that is guaranteed to work with SMB filesystems. If you have many +// events in quick succession this may not be enough, and you will have to use +// [WithBufferSize] to increase the value. +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, and you may + // want to wait until you've stopped receiving them + // (see the dedup example in cmd/fsnotify). + // + // Some systems may send Write event for directories + // when the directory content changes. + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // when a file is truncated. On Windows it's never + // sent. + Events chan Event + + // Errors sends any errors. + // + // ErrEventOverflow is used to indicate there are too many events: + // + // - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl) + // - windows: The buffer size is too small; WithBufferSize() can be used to increase it. + // - kqueue, fen: Not used. + Errors chan error +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + return nil, errors.New("fsnotify not supported on the current platform") +} + +// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events +// channel. +// +// The main use case for this is situations with a very large number of events +// where the kernel buffer size can't be increased (e.g. due to lack of +// permissions). An unbuffered Watcher will perform better for almost all use +// cases, and whenever possible you will be better off increasing the kernel +// buffers instead of adding a large userspace buffer. +func NewBufferedWatcher(sz uint) (*Watcher, error) { return NewWatcher() } + +// Close removes all watches and closes the Events channel. +func (w *Watcher) Close() error { return nil } + +// WatchList returns all paths explicitly added with [Watcher.Add] (and are not +// yet removed). +// +// Returns nil if [Watcher.Close] was called. +func (w *Watcher) WatchList() []string { return nil } + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; watching it more than once is a no-op and will +// not return an error. Paths that do not yet exist on the filesystem cannot be +// watched. +// +// A watch will be automatically removed if the watched path is deleted or +// renamed. The exception is the Windows backend, which doesn't remove the +// watcher on renames. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// Returns [ErrClosed] if [Watcher.Close] was called. +// +// See [Watcher.AddWith] for a version that allows adding options. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many programs (especially editors) update files atomically: it +// will write to a temporary file which is then moved to to destination, +// overwriting the original (or some variant thereof). The watcher on the +// original file is now lost, as that no longer exists. +// +// The upshot of this is that a power failure or crash won't leave a +// half-written file. +// +// Watch the parent directory and use Event.Name to filter out files you're not +// interested in. There is an example of this in cmd/fsnotify/file.go. +func (w *Watcher) Add(name string) error { return nil } + +// AddWith is like [Watcher.Add], but allows adding options. When using Add() +// the defaults described below are used. +// +// Possible options are: +// +// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on +// other platforms. The default is 64K (65536 bytes). +func (w *Watcher) AddWith(name string, opts ...addOpt) error { return nil } + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +// +// Returns nil if [Watcher.Close] was called. +func (w *Watcher) Remove(name string) error { return nil } diff --git a/vendor/github.com/fsnotify/fsnotify/backend_windows.go b/vendor/github.com/fsnotify/fsnotify/backend_windows.go new file mode 100644 index 00000000..9bc91e5d --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_windows.go @@ -0,0 +1,827 @@ +//go:build windows +// +build windows + +// Windows backend based on ReadDirectoryChangesW() +// +// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw +// +// Note: the documentation on the Watcher type and methods is generated from +// mkdoc.zsh + +package fsnotify + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "reflect" + "runtime" + "strings" + "sync" + "unsafe" + + "golang.org/x/sys/windows" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # Windows notes +// +// Paths can be added as "C:\path\to\dir", but forward slashes +// ("C:/path/to/dir") will also work. +// +// When a watched directory is removed it will always send an event for the +// directory itself, but may not send events for all files in that directory. +// Sometimes it will send events for all times, sometimes it will send no +// events, and often only for some files. +// +// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest +// value that is guaranteed to work with SMB filesystems. If you have many +// events in quick succession this may not be enough, and you will have to use +// [WithBufferSize] to increase the value. +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, and you may + // want to wait until you've stopped receiving them + // (see the dedup example in cmd/fsnotify). + // + // Some systems may send Write event for directories + // when the directory content changes. + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // when a file is truncated. On Windows it's never + // sent. + Events chan Event + + // Errors sends any errors. + // + // ErrEventOverflow is used to indicate there are too many events: + // + // - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl) + // - windows: The buffer size is too small; WithBufferSize() can be used to increase it. + // - kqueue, fen: Not used. + Errors chan error + + port windows.Handle // Handle to completion port + input chan *input // Inputs to the reader are sent on this channel + quit chan chan<- error + + mu sync.Mutex // Protects access to watches, closed + watches watchMap // Map of watches (key: i-number) + closed bool // Set to true when Close() is first called +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + return NewBufferedWatcher(50) +} + +// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events +// channel. +// +// The main use case for this is situations with a very large number of events +// where the kernel buffer size can't be increased (e.g. due to lack of +// permissions). An unbuffered Watcher will perform better for almost all use +// cases, and whenever possible you will be better off increasing the kernel +// buffers instead of adding a large userspace buffer. +func NewBufferedWatcher(sz uint) (*Watcher, error) { + port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0) + if err != nil { + return nil, os.NewSyscallError("CreateIoCompletionPort", err) + } + w := &Watcher{ + port: port, + watches: make(watchMap), + input: make(chan *input, 1), + Events: make(chan Event, sz), + Errors: make(chan error), + quit: make(chan chan<- error, 1), + } + go w.readEvents() + return w, nil +} + +func (w *Watcher) isClosed() bool { + w.mu.Lock() + defer w.mu.Unlock() + return w.closed +} + +func (w *Watcher) sendEvent(name string, mask uint64) bool { + if mask == 0 { + return false + } + + event := w.newEvent(name, uint32(mask)) + select { + case ch := <-w.quit: + w.quit <- ch + case w.Events <- event: + } + return true +} + +// Returns true if the error was sent, or false if watcher is closed. +func (w *Watcher) sendError(err error) bool { + select { + case w.Errors <- err: + return true + case <-w.quit: + } + return false +} + +// Close removes all watches and closes the Events channel. +func (w *Watcher) Close() error { + if w.isClosed() { + return nil + } + + w.mu.Lock() + w.closed = true + w.mu.Unlock() + + // Send "quit" message to the reader goroutine + ch := make(chan error) + w.quit <- ch + if err := w.wakeupReader(); err != nil { + return err + } + return <-ch +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; watching it more than once is a no-op and will +// not return an error. Paths that do not yet exist on the filesystem cannot be +// watched. +// +// A watch will be automatically removed if the watched path is deleted or +// renamed. The exception is the Windows backend, which doesn't remove the +// watcher on renames. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// Returns [ErrClosed] if [Watcher.Close] was called. +// +// See [Watcher.AddWith] for a version that allows adding options. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many programs (especially editors) update files atomically: it +// will write to a temporary file which is then moved to to destination, +// overwriting the original (or some variant thereof). The watcher on the +// original file is now lost, as that no longer exists. +// +// The upshot of this is that a power failure or crash won't leave a +// half-written file. +// +// Watch the parent directory and use Event.Name to filter out files you're not +// interested in. There is an example of this in cmd/fsnotify/file.go. +func (w *Watcher) Add(name string) error { return w.AddWith(name) } + +// AddWith is like [Watcher.Add], but allows adding options. When using Add() +// the defaults described below are used. +// +// Possible options are: +// +// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on +// other platforms. The default is 64K (65536 bytes). +func (w *Watcher) AddWith(name string, opts ...addOpt) error { + if w.isClosed() { + return ErrClosed + } + + with := getOptions(opts...) + if with.bufsize < 4096 { + return fmt.Errorf("fsnotify.WithBufferSize: buffer size cannot be smaller than 4096 bytes") + } + + in := &input{ + op: opAddWatch, + path: filepath.Clean(name), + flags: sysFSALLEVENTS, + reply: make(chan error), + bufsize: with.bufsize, + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +// +// Returns nil if [Watcher.Close] was called. +func (w *Watcher) Remove(name string) error { + if w.isClosed() { + return nil + } + + in := &input{ + op: opRemoveWatch, + path: filepath.Clean(name), + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +// WatchList returns all paths explicitly added with [Watcher.Add] (and are not +// yet removed). +// +// Returns nil if [Watcher.Close] was called. +func (w *Watcher) WatchList() []string { + if w.isClosed() { + return nil + } + + w.mu.Lock() + defer w.mu.Unlock() + + entries := make([]string, 0, len(w.watches)) + for _, entry := range w.watches { + for _, watchEntry := range entry { + entries = append(entries, watchEntry.path) + } + } + + return entries +} + +// These options are from the old golang.org/x/exp/winfsnotify, where you could +// add various options to the watch. This has long since been removed. +// +// The "sys" in the name is misleading as they're not part of any "system". +// +// This should all be removed at some point, and just use windows.FILE_NOTIFY_* +const ( + sysFSALLEVENTS = 0xfff + sysFSCREATE = 0x100 + sysFSDELETE = 0x200 + sysFSDELETESELF = 0x400 + sysFSMODIFY = 0x2 + sysFSMOVE = 0xc0 + sysFSMOVEDFROM = 0x40 + sysFSMOVEDTO = 0x80 + sysFSMOVESELF = 0x800 + sysFSIGNORED = 0x8000 +) + +func (w *Watcher) newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO { + e.Op |= Create + } + if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF { + e.Op |= Remove + } + if mask&sysFSMODIFY == sysFSMODIFY { + e.Op |= Write + } + if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM { + e.Op |= Rename + } + return e +} + +const ( + opAddWatch = iota + opRemoveWatch +) + +const ( + provisional uint64 = 1 << (32 + iota) +) + +type input struct { + op int + path string + flags uint32 + bufsize int + reply chan error +} + +type inode struct { + handle windows.Handle + volume uint32 + index uint64 +} + +type watch struct { + ov windows.Overlapped + ino *inode // i-number + recurse bool // Recursive watch? + path string // Directory path + mask uint64 // Directory itself is being watched with these notify flags + names map[string]uint64 // Map of names being watched and their notify flags + rename string // Remembers the old name while renaming a file + buf []byte // buffer, allocated later +} + +type ( + indexMap map[uint64]*watch + watchMap map[uint32]indexMap +) + +func (w *Watcher) wakeupReader() error { + err := windows.PostQueuedCompletionStatus(w.port, 0, 0, nil) + if err != nil { + return os.NewSyscallError("PostQueuedCompletionStatus", err) + } + return nil +} + +func (w *Watcher) getDir(pathname string) (dir string, err error) { + attr, err := windows.GetFileAttributes(windows.StringToUTF16Ptr(pathname)) + if err != nil { + return "", os.NewSyscallError("GetFileAttributes", err) + } + if attr&windows.FILE_ATTRIBUTE_DIRECTORY != 0 { + dir = pathname + } else { + dir, _ = filepath.Split(pathname) + dir = filepath.Clean(dir) + } + return +} + +func (w *Watcher) getIno(path string) (ino *inode, err error) { + h, err := windows.CreateFile(windows.StringToUTF16Ptr(path), + windows.FILE_LIST_DIRECTORY, + windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, + nil, windows.OPEN_EXISTING, + windows.FILE_FLAG_BACKUP_SEMANTICS|windows.FILE_FLAG_OVERLAPPED, 0) + if err != nil { + return nil, os.NewSyscallError("CreateFile", err) + } + + var fi windows.ByHandleFileInformation + err = windows.GetFileInformationByHandle(h, &fi) + if err != nil { + windows.CloseHandle(h) + return nil, os.NewSyscallError("GetFileInformationByHandle", err) + } + ino = &inode{ + handle: h, + volume: fi.VolumeSerialNumber, + index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), + } + return ino, nil +} + +// Must run within the I/O thread. +func (m watchMap) get(ino *inode) *watch { + if i := m[ino.volume]; i != nil { + return i[ino.index] + } + return nil +} + +// Must run within the I/O thread. +func (m watchMap) set(ino *inode, watch *watch) { + i := m[ino.volume] + if i == nil { + i = make(indexMap) + m[ino.volume] = i + } + i[ino.index] = watch +} + +// Must run within the I/O thread. +func (w *Watcher) addWatch(pathname string, flags uint64, bufsize int) error { + //pathname, recurse := recursivePath(pathname) + recurse := false + + dir, err := w.getDir(pathname) + if err != nil { + return err + } + + ino, err := w.getIno(dir) + if err != nil { + return err + } + w.mu.Lock() + watchEntry := w.watches.get(ino) + w.mu.Unlock() + if watchEntry == nil { + _, err := windows.CreateIoCompletionPort(ino.handle, w.port, 0, 0) + if err != nil { + windows.CloseHandle(ino.handle) + return os.NewSyscallError("CreateIoCompletionPort", err) + } + watchEntry = &watch{ + ino: ino, + path: dir, + names: make(map[string]uint64), + recurse: recurse, + buf: make([]byte, bufsize), + } + w.mu.Lock() + w.watches.set(ino, watchEntry) + w.mu.Unlock() + flags |= provisional + } else { + windows.CloseHandle(ino.handle) + } + if pathname == dir { + watchEntry.mask |= flags + } else { + watchEntry.names[filepath.Base(pathname)] |= flags + } + + err = w.startRead(watchEntry) + if err != nil { + return err + } + + if pathname == dir { + watchEntry.mask &= ^provisional + } else { + watchEntry.names[filepath.Base(pathname)] &= ^provisional + } + return nil +} + +// Must run within the I/O thread. +func (w *Watcher) remWatch(pathname string) error { + pathname, recurse := recursivePath(pathname) + + dir, err := w.getDir(pathname) + if err != nil { + return err + } + ino, err := w.getIno(dir) + if err != nil { + return err + } + + w.mu.Lock() + watch := w.watches.get(ino) + w.mu.Unlock() + + if recurse && !watch.recurse { + return fmt.Errorf("can't use \\... with non-recursive watch %q", pathname) + } + + err = windows.CloseHandle(ino.handle) + if err != nil { + w.sendError(os.NewSyscallError("CloseHandle", err)) + } + if watch == nil { + return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname) + } + if pathname == dir { + w.sendEvent(watch.path, watch.mask&sysFSIGNORED) + watch.mask = 0 + } else { + name := filepath.Base(pathname) + w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED) + delete(watch.names, name) + } + + return w.startRead(watch) +} + +// Must run within the I/O thread. +func (w *Watcher) deleteWatch(watch *watch) { + for name, mask := range watch.names { + if mask&provisional == 0 { + w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED) + } + delete(watch.names, name) + } + if watch.mask != 0 { + if watch.mask&provisional == 0 { + w.sendEvent(watch.path, watch.mask&sysFSIGNORED) + } + watch.mask = 0 + } +} + +// Must run within the I/O thread. +func (w *Watcher) startRead(watch *watch) error { + err := windows.CancelIo(watch.ino.handle) + if err != nil { + w.sendError(os.NewSyscallError("CancelIo", err)) + w.deleteWatch(watch) + } + mask := w.toWindowsFlags(watch.mask) + for _, m := range watch.names { + mask |= w.toWindowsFlags(m) + } + if mask == 0 { + err := windows.CloseHandle(watch.ino.handle) + if err != nil { + w.sendError(os.NewSyscallError("CloseHandle", err)) + } + w.mu.Lock() + delete(w.watches[watch.ino.volume], watch.ino.index) + w.mu.Unlock() + return nil + } + + // We need to pass the array, rather than the slice. + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&watch.buf)) + rdErr := windows.ReadDirectoryChanges(watch.ino.handle, + (*byte)(unsafe.Pointer(hdr.Data)), uint32(hdr.Len), + watch.recurse, mask, nil, &watch.ov, 0) + if rdErr != nil { + err := os.NewSyscallError("ReadDirectoryChanges", rdErr) + if rdErr == windows.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { + // Watched directory was probably removed + w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) + err = nil + } + w.deleteWatch(watch) + w.startRead(watch) + return err + } + return nil +} + +// readEvents reads from the I/O completion port, converts the +// received events into Event objects and sends them via the Events channel. +// Entry point to the I/O thread. +func (w *Watcher) readEvents() { + var ( + n uint32 + key uintptr + ov *windows.Overlapped + ) + runtime.LockOSThread() + + for { + // This error is handled after the watch == nil check below. + qErr := windows.GetQueuedCompletionStatus(w.port, &n, &key, &ov, windows.INFINITE) + + watch := (*watch)(unsafe.Pointer(ov)) + if watch == nil { + select { + case ch := <-w.quit: + w.mu.Lock() + var indexes []indexMap + for _, index := range w.watches { + indexes = append(indexes, index) + } + w.mu.Unlock() + for _, index := range indexes { + for _, watch := range index { + w.deleteWatch(watch) + w.startRead(watch) + } + } + + err := windows.CloseHandle(w.port) + if err != nil { + err = os.NewSyscallError("CloseHandle", err) + } + close(w.Events) + close(w.Errors) + ch <- err + return + case in := <-w.input: + switch in.op { + case opAddWatch: + in.reply <- w.addWatch(in.path, uint64(in.flags), in.bufsize) + case opRemoveWatch: + in.reply <- w.remWatch(in.path) + } + default: + } + continue + } + + switch qErr { + case nil: + // No error + case windows.ERROR_MORE_DATA: + if watch == nil { + w.sendError(errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")) + } else { + // The i/o succeeded but the buffer is full. + // In theory we should be building up a full packet. + // In practice we can get away with just carrying on. + n = uint32(unsafe.Sizeof(watch.buf)) + } + case windows.ERROR_ACCESS_DENIED: + // Watched directory was probably removed + w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) + w.deleteWatch(watch) + w.startRead(watch) + continue + case windows.ERROR_OPERATION_ABORTED: + // CancelIo was called on this handle + continue + default: + w.sendError(os.NewSyscallError("GetQueuedCompletionPort", qErr)) + continue + } + + var offset uint32 + for { + if n == 0 { + w.sendError(ErrEventOverflow) + break + } + + // Point "raw" to the event in the buffer + raw := (*windows.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) + + // Create a buf that is the size of the path name + size := int(raw.FileNameLength / 2) + var buf []uint16 + // TODO: Use unsafe.Slice in Go 1.17; https://stackoverflow.com/questions/51187973 + sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + sh.Data = uintptr(unsafe.Pointer(&raw.FileName)) + sh.Len = size + sh.Cap = size + name := windows.UTF16ToString(buf) + fullname := filepath.Join(watch.path, name) + + var mask uint64 + switch raw.Action { + case windows.FILE_ACTION_REMOVED: + mask = sysFSDELETESELF + case windows.FILE_ACTION_MODIFIED: + mask = sysFSMODIFY + case windows.FILE_ACTION_RENAMED_OLD_NAME: + watch.rename = name + case windows.FILE_ACTION_RENAMED_NEW_NAME: + // Update saved path of all sub-watches. + old := filepath.Join(watch.path, watch.rename) + w.mu.Lock() + for _, watchMap := range w.watches { + for _, ww := range watchMap { + if strings.HasPrefix(ww.path, old) { + ww.path = filepath.Join(fullname, strings.TrimPrefix(ww.path, old)) + } + } + } + w.mu.Unlock() + + if watch.names[watch.rename] != 0 { + watch.names[name] |= watch.names[watch.rename] + delete(watch.names, watch.rename) + mask = sysFSMOVESELF + } + } + + sendNameEvent := func() { + w.sendEvent(fullname, watch.names[name]&mask) + } + if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME { + sendNameEvent() + } + if raw.Action == windows.FILE_ACTION_REMOVED { + w.sendEvent(fullname, watch.names[name]&sysFSIGNORED) + delete(watch.names, name) + } + + w.sendEvent(fullname, watch.mask&w.toFSnotifyFlags(raw.Action)) + if raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME { + fullname = filepath.Join(watch.path, watch.rename) + sendNameEvent() + } + + // Move to the next event in the buffer + if raw.NextEntryOffset == 0 { + break + } + offset += raw.NextEntryOffset + + // Error! + if offset >= n { + //lint:ignore ST1005 Windows should be capitalized + w.sendError(errors.New( + "Windows system assumed buffer larger than it is, events have likely been missed")) + break + } + } + + if err := w.startRead(watch); err != nil { + w.sendError(err) + } + } +} + +func (w *Watcher) toWindowsFlags(mask uint64) uint32 { + var m uint32 + if mask&sysFSMODIFY != 0 { + m |= windows.FILE_NOTIFY_CHANGE_LAST_WRITE + } + if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 { + m |= windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME + } + return m +} + +func (w *Watcher) toFSnotifyFlags(action uint32) uint64 { + switch action { + case windows.FILE_ACTION_ADDED: + return sysFSCREATE + case windows.FILE_ACTION_REMOVED: + return sysFSDELETE + case windows.FILE_ACTION_MODIFIED: + return sysFSMODIFY + case windows.FILE_ACTION_RENAMED_OLD_NAME: + return sysFSMOVEDFROM + case windows.FILE_ACTION_RENAMED_NEW_NAME: + return sysFSMOVEDTO + } + return 0 +} diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/vendor/github.com/fsnotify/fsnotify/fsnotify.go new file mode 100644 index 00000000..24c99cc4 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/fsnotify.go @@ -0,0 +1,146 @@ +// Package fsnotify provides a cross-platform interface for file system +// notifications. +// +// Currently supported systems: +// +// Linux 2.6.32+ via inotify +// BSD, macOS via kqueue +// Windows via ReadDirectoryChangesW +// illumos via FEN +package fsnotify + +import ( + "errors" + "fmt" + "path/filepath" + "strings" +) + +// Event represents a file system notification. +type Event struct { + // Path to the file or directory. + // + // Paths are relative to the input; for example with Add("dir") the Name + // will be set to "dir/file" if you create that file, but if you use + // Add("/path/to/dir") it will be "/path/to/dir/file". + Name string + + // File operation that triggered the event. + // + // This is a bitmask and some systems may send multiple operations at once. + // Use the Event.Has() method instead of comparing with ==. + Op Op +} + +// Op describes a set of file operations. +type Op uint32 + +// The operations fsnotify can trigger; see the documentation on [Watcher] for a +// full description, and check them with [Event.Has]. +const ( + // A new pathname was created. + Create Op = 1 << iota + + // The pathname was written to; this does *not* mean the write has finished, + // and a write can be followed by more writes. + Write + + // The path was removed; any watches on it will be removed. Some "remove" + // operations may trigger a Rename if the file is actually moved (for + // example "remove to trash" is often a rename). + Remove + + // The path was renamed to something else; any watched on it will be + // removed. + Rename + + // File attributes were changed. + // + // It's generally not recommended to take action on this event, as it may + // get triggered very frequently by some software. For example, Spotlight + // indexing on macOS, anti-virus software, backup software, etc. + Chmod +) + +// Common errors that can be reported. +var ( + ErrNonExistentWatch = errors.New("fsnotify: can't remove non-existent watch") + ErrEventOverflow = errors.New("fsnotify: queue or buffer overflow") + ErrClosed = errors.New("fsnotify: watcher already closed") +) + +func (o Op) String() string { + var b strings.Builder + if o.Has(Create) { + b.WriteString("|CREATE") + } + if o.Has(Remove) { + b.WriteString("|REMOVE") + } + if o.Has(Write) { + b.WriteString("|WRITE") + } + if o.Has(Rename) { + b.WriteString("|RENAME") + } + if o.Has(Chmod) { + b.WriteString("|CHMOD") + } + if b.Len() == 0 { + return "[no events]" + } + return b.String()[1:] +} + +// Has reports if this operation has the given operation. +func (o Op) Has(h Op) bool { return o&h != 0 } + +// Has reports if this event has the given operation. +func (e Event) Has(op Op) bool { return e.Op.Has(op) } + +// String returns a string representation of the event with their path. +func (e Event) String() string { + return fmt.Sprintf("%-13s %q", e.Op.String(), e.Name) +} + +type ( + addOpt func(opt *withOpts) + withOpts struct { + bufsize int + } +) + +var defaultOpts = withOpts{ + bufsize: 65536, // 64K +} + +func getOptions(opts ...addOpt) withOpts { + with := defaultOpts + for _, o := range opts { + o(&with) + } + return with +} + +// WithBufferSize sets the [ReadDirectoryChangesW] buffer size. +// +// This only has effect on Windows systems, and is a no-op for other backends. +// +// The default value is 64K (65536 bytes) which is the highest value that works +// on all filesystems and should be enough for most applications, but if you +// have a large burst of events it may not be enough. You can increase it if +// you're hitting "queue or buffer overflow" errors ([ErrEventOverflow]). +// +// [ReadDirectoryChangesW]: https://learn.microsoft.com/en-gb/windows/win32/api/winbase/nf-winbase-readdirectorychangesw +func WithBufferSize(bytes int) addOpt { + return func(opt *withOpts) { opt.bufsize = bytes } +} + +// Check if this path is recursive (ends with "/..." or "\..."), and return the +// path with the /... stripped. +func recursivePath(path string) (string, bool) { + if filepath.Base(path) == "..." { + return filepath.Dir(path), true + } + return path, false +} diff --git a/vendor/github.com/fsnotify/fsnotify/mkdoc.zsh b/vendor/github.com/fsnotify/fsnotify/mkdoc.zsh new file mode 100644 index 00000000..99012ae6 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/mkdoc.zsh @@ -0,0 +1,259 @@ +#!/usr/bin/env zsh +[ "${ZSH_VERSION:-}" = "" ] && echo >&2 "Only works with zsh" && exit 1 +setopt err_exit no_unset pipefail extended_glob + +# Simple script to update the godoc comments on all watchers so you don't need +# to update the same comment 5 times. + +watcher=$(</tmp/x + print -r -- $cmt >>/tmp/x + tail -n+$(( end + 1 )) $file >>/tmp/x + mv /tmp/x $file + done +} + +set-cmt '^type Watcher struct ' $watcher +set-cmt '^func NewWatcher(' $new +set-cmt '^func NewBufferedWatcher(' $newbuffered +set-cmt '^func (w \*Watcher) Add(' $add +set-cmt '^func (w \*Watcher) AddWith(' $addwith +set-cmt '^func (w \*Watcher) Remove(' $remove +set-cmt '^func (w \*Watcher) Close(' $close +set-cmt '^func (w \*Watcher) WatchList(' $watchlist +set-cmt '^[[:space:]]*Events *chan Event$' $events +set-cmt '^[[:space:]]*Errors *chan error$' $errors diff --git a/vendor/github.com/fsnotify/fsnotify/system_bsd.go b/vendor/github.com/fsnotify/fsnotify/system_bsd.go new file mode 100644 index 00000000..4322b0b8 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/system_bsd.go @@ -0,0 +1,8 @@ +//go:build freebsd || openbsd || netbsd || dragonfly +// +build freebsd openbsd netbsd dragonfly + +package fsnotify + +import "golang.org/x/sys/unix" + +const openMode = unix.O_NONBLOCK | unix.O_RDONLY | unix.O_CLOEXEC diff --git a/vendor/github.com/fsnotify/fsnotify/system_darwin.go b/vendor/github.com/fsnotify/fsnotify/system_darwin.go new file mode 100644 index 00000000..5da5ffa7 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/system_darwin.go @@ -0,0 +1,9 @@ +//go:build darwin +// +build darwin + +package fsnotify + +import "golang.org/x/sys/unix" + +// note: this constant is not defined on BSD +const openMode = unix.O_EVTONLY | unix.O_CLOEXEC diff --git a/vendor/github.com/opencontainers/runtime-spec/LICENSE b/vendor/github.com/opencontainers/runtime-spec/LICENSE new file mode 100644 index 00000000..bdc40365 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-spec/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor 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, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 The Linux Foundation. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go new file mode 100644 index 00000000..1aa0693b --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go @@ -0,0 +1,917 @@ +package specs + +import "os" + +// Spec is the base configuration for the container. +type Spec struct { + // Version of the Open Container Initiative Runtime Specification with which the bundle complies. + Version string `json:"ociVersion"` + // Process configures the container process. + Process *Process `json:"process,omitempty"` + // Root configures the container's root filesystem. + Root *Root `json:"root,omitempty"` + // Hostname configures the container's hostname. + Hostname string `json:"hostname,omitempty"` + // Domainname configures the container's domainname. + Domainname string `json:"domainname,omitempty"` + // Mounts configures additional mounts (on top of Root). + Mounts []Mount `json:"mounts,omitempty"` + // Hooks configures callbacks for container lifecycle events. + Hooks *Hooks `json:"hooks,omitempty" platform:"linux,solaris,zos"` + // Annotations contains arbitrary metadata for the container. + Annotations map[string]string `json:"annotations,omitempty"` + + // Linux is platform-specific configuration for Linux based containers. + Linux *Linux `json:"linux,omitempty" platform:"linux"` + // Solaris is platform-specific configuration for Solaris based containers. + Solaris *Solaris `json:"solaris,omitempty" platform:"solaris"` + // Windows is platform-specific configuration for Windows based containers. + Windows *Windows `json:"windows,omitempty" platform:"windows"` + // VM specifies configuration for virtual-machine-based containers. + VM *VM `json:"vm,omitempty" platform:"vm"` + // ZOS is platform-specific configuration for z/OS based containers. + ZOS *ZOS `json:"zos,omitempty" platform:"zos"` +} + +// Scheduler represents the scheduling attributes for a process. It is based on +// the Linux sched_setattr(2) syscall. +type Scheduler struct { + // Policy represents the scheduling policy (e.g., SCHED_FIFO, SCHED_RR, SCHED_OTHER). + Policy LinuxSchedulerPolicy `json:"policy"` + + // Nice is the nice value for the process, which affects its priority. + Nice int32 `json:"nice,omitempty"` + + // Priority represents the static priority of the process. + Priority int32 `json:"priority,omitempty"` + + // Flags is an array of scheduling flags. + Flags []LinuxSchedulerFlag `json:"flags,omitempty"` + + // The following ones are used by the DEADLINE scheduler. + + // Runtime is the amount of time in nanoseconds during which the process + // is allowed to run in a given period. + Runtime uint64 `json:"runtime,omitempty"` + + // Deadline is the absolute deadline for the process to complete its execution. + Deadline uint64 `json:"deadline,omitempty"` + + // Period is the length of the period in nanoseconds used for determining the process runtime. + Period uint64 `json:"period,omitempty"` +} + +// Process contains information to start a specific application inside the container. +type Process struct { + // Terminal creates an interactive terminal for the container. + Terminal bool `json:"terminal,omitempty"` + // ConsoleSize specifies the size of the console. + ConsoleSize *Box `json:"consoleSize,omitempty"` + // User specifies user information for the process. + User User `json:"user"` + // Args specifies the binary and arguments for the application to execute. + Args []string `json:"args,omitempty"` + // CommandLine specifies the full command line for the application to execute on Windows. + CommandLine string `json:"commandLine,omitempty" platform:"windows"` + // Env populates the process environment for the process. + Env []string `json:"env,omitempty"` + // Cwd is the current working directory for the process and must be + // relative to the container's root. + Cwd string `json:"cwd"` + // Capabilities are Linux capabilities that are kept for the process. + Capabilities *LinuxCapabilities `json:"capabilities,omitempty" platform:"linux"` + // Rlimits specifies rlimit options to apply to the process. + Rlimits []POSIXRlimit `json:"rlimits,omitempty" platform:"linux,solaris,zos"` + // NoNewPrivileges controls whether additional privileges could be gained by processes in the container. + NoNewPrivileges bool `json:"noNewPrivileges,omitempty" platform:"linux,zos"` + // ApparmorProfile specifies the apparmor profile for the container. + ApparmorProfile string `json:"apparmorProfile,omitempty" platform:"linux"` + // Specify an oom_score_adj for the container. + OOMScoreAdj *int `json:"oomScoreAdj,omitempty" platform:"linux"` + // Scheduler specifies the scheduling attributes for a process + Scheduler *Scheduler `json:"scheduler,omitempty" platform:"linux"` + // SelinuxLabel specifies the selinux context that the container process is run as. + SelinuxLabel string `json:"selinuxLabel,omitempty" platform:"linux"` + // IOPriority contains the I/O priority settings for the cgroup. + IOPriority *LinuxIOPriority `json:"ioPriority,omitempty" platform:"linux"` + // ExecCPUAffinity specifies CPU affinity for exec processes. + ExecCPUAffinity *CPUAffinity `json:"execCPUAffinity,omitempty" platform:"linux"` +} + +// LinuxCapabilities specifies the list of allowed capabilities that are kept for a process. +// https://man7.org/linux/man-pages/man7/capabilities.7.html +type LinuxCapabilities struct { + // Bounding is the set of capabilities checked by the kernel. + Bounding []string `json:"bounding,omitempty" platform:"linux"` + // Effective is the set of capabilities checked by the kernel. + Effective []string `json:"effective,omitempty" platform:"linux"` + // Inheritable is the capabilities preserved across execve. + Inheritable []string `json:"inheritable,omitempty" platform:"linux"` + // Permitted is the limiting superset for effective capabilities. + Permitted []string `json:"permitted,omitempty" platform:"linux"` + // Ambient is the ambient set of capabilities that are kept. + Ambient []string `json:"ambient,omitempty" platform:"linux"` +} + +// IOPriority represents I/O priority settings for the container's processes within the process group. +type LinuxIOPriority struct { + Class IOPriorityClass `json:"class"` + Priority int `json:"priority"` +} + +// IOPriorityClass represents an I/O scheduling class. +type IOPriorityClass string + +// Possible values for IOPriorityClass. +const ( + IOPRIO_CLASS_RT IOPriorityClass = "IOPRIO_CLASS_RT" + IOPRIO_CLASS_BE IOPriorityClass = "IOPRIO_CLASS_BE" + IOPRIO_CLASS_IDLE IOPriorityClass = "IOPRIO_CLASS_IDLE" +) + +// CPUAffinity specifies process' CPU affinity. +type CPUAffinity struct { + Initial string `json:"initial,omitempty"` + Final string `json:"final,omitempty"` +} + +// Box specifies dimensions of a rectangle. Used for specifying the size of a console. +type Box struct { + // Height is the vertical dimension of a box. + Height uint `json:"height"` + // Width is the horizontal dimension of a box. + Width uint `json:"width"` +} + +// User specifies specific user (and group) information for the container process. +type User struct { + // UID is the user id. + UID uint32 `json:"uid" platform:"linux,solaris,zos"` + // GID is the group id. + GID uint32 `json:"gid" platform:"linux,solaris,zos"` + // Umask is the umask for the init process. + Umask *uint32 `json:"umask,omitempty" platform:"linux,solaris,zos"` + // AdditionalGids are additional group ids set for the container's process. + AdditionalGids []uint32 `json:"additionalGids,omitempty" platform:"linux,solaris"` + // Username is the user name. + Username string `json:"username,omitempty" platform:"windows"` +} + +// Root contains information about the container's root filesystem on the host. +type Root struct { + // Path is the absolute path to the container's root filesystem. + Path string `json:"path"` + // Readonly makes the root filesystem for the container readonly before the process is executed. + Readonly bool `json:"readonly,omitempty"` +} + +// Mount specifies a mount for a container. +type Mount struct { + // Destination is the absolute path where the mount will be placed in the container. + Destination string `json:"destination"` + // Type specifies the mount kind. + Type string `json:"type,omitempty" platform:"linux,solaris,zos"` + // Source specifies the source path of the mount. + Source string `json:"source,omitempty"` + // Options are fstab style mount options. + Options []string `json:"options,omitempty"` + + // UID/GID mappings used for changing file owners w/o calling chown, fs should support it. + // Every mount point could have its own mapping. + UIDMappings []LinuxIDMapping `json:"uidMappings,omitempty" platform:"linux"` + GIDMappings []LinuxIDMapping `json:"gidMappings,omitempty" platform:"linux"` +} + +// Hook specifies a command that is run at a particular event in the lifecycle of a container +type Hook struct { + Path string `json:"path"` + Args []string `json:"args,omitempty"` + Env []string `json:"env,omitempty"` + Timeout *int `json:"timeout,omitempty"` +} + +// Hooks specifies a command that is run in the container at a particular event in the lifecycle of a container +// Hooks for container setup and teardown +type Hooks struct { + // Prestart is Deprecated. Prestart is a list of hooks to be run before the container process is executed. + // It is called in the Runtime Namespace + // + // Deprecated: use [Hooks.CreateRuntime], [Hooks.CreateContainer], and + // [Hooks.StartContainer] instead, which allow more granular hook control + // during the create and start phase. + Prestart []Hook `json:"prestart,omitempty"` + // CreateRuntime is a list of hooks to be run after the container has been created but before pivot_root or any equivalent operation has been called + // It is called in the Runtime Namespace + CreateRuntime []Hook `json:"createRuntime,omitempty"` + // CreateContainer is a list of hooks to be run after the container has been created but before pivot_root or any equivalent operation has been called + // It is called in the Container Namespace + CreateContainer []Hook `json:"createContainer,omitempty"` + // StartContainer is a list of hooks to be run after the start operation is called but before the container process is started + // It is called in the Container Namespace + StartContainer []Hook `json:"startContainer,omitempty"` + // Poststart is a list of hooks to be run after the container process is started. + // It is called in the Runtime Namespace + Poststart []Hook `json:"poststart,omitempty"` + // Poststop is a list of hooks to be run after the container process exits. + // It is called in the Runtime Namespace + Poststop []Hook `json:"poststop,omitempty"` +} + +// Linux contains platform-specific configuration for Linux based containers. +type Linux struct { + // UIDMapping specifies user mappings for supporting user namespaces. + UIDMappings []LinuxIDMapping `json:"uidMappings,omitempty"` + // GIDMapping specifies group mappings for supporting user namespaces. + GIDMappings []LinuxIDMapping `json:"gidMappings,omitempty"` + // Sysctl are a set of key value pairs that are set for the container on start + Sysctl map[string]string `json:"sysctl,omitempty"` + // Resources contain cgroup information for handling resource constraints + // for the container + Resources *LinuxResources `json:"resources,omitempty"` + // CgroupsPath specifies the path to cgroups that are created and/or joined by the container. + // The path is expected to be relative to the cgroups mountpoint. + // If resources are specified, the cgroups at CgroupsPath will be updated based on resources. + CgroupsPath string `json:"cgroupsPath,omitempty"` + // Namespaces contains the namespaces that are created and/or joined by the container + Namespaces []LinuxNamespace `json:"namespaces,omitempty"` + // Devices are a list of device nodes that are created for the container + Devices []LinuxDevice `json:"devices,omitempty"` + // Seccomp specifies the seccomp security settings for the container. + Seccomp *LinuxSeccomp `json:"seccomp,omitempty"` + // RootfsPropagation is the rootfs mount propagation mode for the container. + RootfsPropagation string `json:"rootfsPropagation,omitempty"` + // MaskedPaths masks over the provided paths inside the container. + MaskedPaths []string `json:"maskedPaths,omitempty"` + // ReadonlyPaths sets the provided paths as RO inside the container. + ReadonlyPaths []string `json:"readonlyPaths,omitempty"` + // MountLabel specifies the selinux context for the mounts in the container. + MountLabel string `json:"mountLabel,omitempty"` + // IntelRdt contains Intel Resource Director Technology (RDT) information for + // handling resource constraints and monitoring metrics (e.g., L3 cache, memory bandwidth) for the container + IntelRdt *LinuxIntelRdt `json:"intelRdt,omitempty"` + // Personality contains configuration for the Linux personality syscall + Personality *LinuxPersonality `json:"personality,omitempty"` + // TimeOffsets specifies the offset for supporting time namespaces. + TimeOffsets map[string]LinuxTimeOffset `json:"timeOffsets,omitempty"` +} + +// LinuxNamespace is the configuration for a Linux namespace +type LinuxNamespace struct { + // Type is the type of namespace + Type LinuxNamespaceType `json:"type"` + // Path is a path to an existing namespace persisted on disk that can be joined + // and is of the same type + Path string `json:"path,omitempty"` +} + +// LinuxNamespaceType is one of the Linux namespaces +type LinuxNamespaceType string + +const ( + // PIDNamespace for isolating process IDs + PIDNamespace LinuxNamespaceType = "pid" + // NetworkNamespace for isolating network devices, stacks, ports, etc + NetworkNamespace LinuxNamespaceType = "network" + // MountNamespace for isolating mount points + MountNamespace LinuxNamespaceType = "mount" + // IPCNamespace for isolating System V IPC, POSIX message queues + IPCNamespace LinuxNamespaceType = "ipc" + // UTSNamespace for isolating hostname and NIS domain name + UTSNamespace LinuxNamespaceType = "uts" + // UserNamespace for isolating user and group IDs + UserNamespace LinuxNamespaceType = "user" + // CgroupNamespace for isolating cgroup hierarchies + CgroupNamespace LinuxNamespaceType = "cgroup" + // TimeNamespace for isolating the clocks + TimeNamespace LinuxNamespaceType = "time" +) + +// LinuxIDMapping specifies UID/GID mappings +type LinuxIDMapping struct { + // ContainerID is the starting UID/GID in the container + ContainerID uint32 `json:"containerID"` + // HostID is the starting UID/GID on the host to be mapped to 'ContainerID' + HostID uint32 `json:"hostID"` + // Size is the number of IDs to be mapped + Size uint32 `json:"size"` +} + +// LinuxTimeOffset specifies the offset for Time Namespace +type LinuxTimeOffset struct { + // Secs is the offset of clock (in secs) in the container + Secs int64 `json:"secs,omitempty"` + // Nanosecs is the additional offset for Secs (in nanosecs) + Nanosecs uint32 `json:"nanosecs,omitempty"` +} + +// POSIXRlimit type and restrictions +type POSIXRlimit struct { + // Type of the rlimit to set + Type string `json:"type"` + // Hard is the hard limit for the specified type + Hard uint64 `json:"hard"` + // Soft is the soft limit for the specified type + Soft uint64 `json:"soft"` +} + +// LinuxHugepageLimit structure corresponds to limiting kernel hugepages. +// Default to reservation limits if supported. Otherwise fallback to page fault limits. +type LinuxHugepageLimit struct { + // Pagesize is the hugepage size. + // Format: "B' (e.g. 64KB, 2MB, 1GB, etc.). + Pagesize string `json:"pageSize"` + // Limit is the limit of "hugepagesize" hugetlb reservations (if supported) or usage. + Limit uint64 `json:"limit"` +} + +// LinuxInterfacePriority for network interfaces +type LinuxInterfacePriority struct { + // Name is the name of the network interface + Name string `json:"name"` + // Priority for the interface + Priority uint32 `json:"priority"` +} + +// LinuxBlockIODevice holds major:minor format supported in blkio cgroup +type LinuxBlockIODevice struct { + // Major is the device's major number. + Major int64 `json:"major"` + // Minor is the device's minor number. + Minor int64 `json:"minor"` +} + +// LinuxWeightDevice struct holds a `major:minor weight` pair for weightDevice +type LinuxWeightDevice struct { + LinuxBlockIODevice + // Weight is the bandwidth rate for the device. + Weight *uint16 `json:"weight,omitempty"` + // LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, CFQ scheduler only + LeafWeight *uint16 `json:"leafWeight,omitempty"` +} + +// LinuxThrottleDevice struct holds a `major:minor rate_per_second` pair +type LinuxThrottleDevice struct { + LinuxBlockIODevice + // Rate is the IO rate limit per cgroup per device + Rate uint64 `json:"rate"` +} + +// LinuxBlockIO for Linux cgroup 'blkio' resource management +type LinuxBlockIO struct { + // Specifies per cgroup weight + Weight *uint16 `json:"weight,omitempty"` + // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, CFQ scheduler only + LeafWeight *uint16 `json:"leafWeight,omitempty"` + // Weight per cgroup per device, can override BlkioWeight + WeightDevice []LinuxWeightDevice `json:"weightDevice,omitempty"` + // IO read rate limit per cgroup per device, bytes per second + ThrottleReadBpsDevice []LinuxThrottleDevice `json:"throttleReadBpsDevice,omitempty"` + // IO write rate limit per cgroup per device, bytes per second + ThrottleWriteBpsDevice []LinuxThrottleDevice `json:"throttleWriteBpsDevice,omitempty"` + // IO read rate limit per cgroup per device, IO per second + ThrottleReadIOPSDevice []LinuxThrottleDevice `json:"throttleReadIOPSDevice,omitempty"` + // IO write rate limit per cgroup per device, IO per second + ThrottleWriteIOPSDevice []LinuxThrottleDevice `json:"throttleWriteIOPSDevice,omitempty"` +} + +// LinuxMemory for Linux cgroup 'memory' resource management +type LinuxMemory struct { + // Memory limit (in bytes). + Limit *int64 `json:"limit,omitempty"` + // Memory reservation or soft_limit (in bytes). + Reservation *int64 `json:"reservation,omitempty"` + // Total memory limit (memory + swap). + Swap *int64 `json:"swap,omitempty"` + // Kernel memory limit (in bytes). + // + // Deprecated: kernel-memory limits are not supported in cgroups v2, and + // were obsoleted in [kernel v5.4]. This field should no longer be used, + // as it may be ignored by runtimes. + // + // [kernel v5.4]: https://github.com/torvalds/linux/commit/0158115f702b0ba208ab0 + Kernel *int64 `json:"kernel,omitempty"` + // Kernel memory limit for tcp (in bytes) + KernelTCP *int64 `json:"kernelTCP,omitempty"` + // How aggressive the kernel will swap memory pages. + Swappiness *uint64 `json:"swappiness,omitempty"` + // DisableOOMKiller disables the OOM killer for out of memory conditions + DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"` + // Enables hierarchical memory accounting + UseHierarchy *bool `json:"useHierarchy,omitempty"` + // CheckBeforeUpdate enables checking if a new memory limit is lower + // than the current usage during update, and if so, rejecting the new + // limit. + CheckBeforeUpdate *bool `json:"checkBeforeUpdate,omitempty"` +} + +// LinuxCPU for Linux cgroup 'cpu' resource management +type LinuxCPU struct { + // CPU shares (relative weight (ratio) vs. other cgroups with cpu shares). + Shares *uint64 `json:"shares,omitempty"` + // CPU hardcap limit (in usecs). Allowed cpu time in a given period. + Quota *int64 `json:"quota,omitempty"` + // CPU hardcap burst limit (in usecs). Allowed accumulated cpu time additionally for burst in a + // given period. + Burst *uint64 `json:"burst,omitempty"` + // CPU period to be used for hardcapping (in usecs). + Period *uint64 `json:"period,omitempty"` + // How much time realtime scheduling may use (in usecs). + RealtimeRuntime *int64 `json:"realtimeRuntime,omitempty"` + // CPU period to be used for realtime scheduling (in usecs). + RealtimePeriod *uint64 `json:"realtimePeriod,omitempty"` + // CPUs to use within the cpuset. Default is to use any CPU available. + Cpus string `json:"cpus,omitempty"` + // List of memory nodes in the cpuset. Default is to use any available memory node. + Mems string `json:"mems,omitempty"` + // cgroups are configured with minimum weight, 0: default behavior, 1: SCHED_IDLE. + Idle *int64 `json:"idle,omitempty"` +} + +// LinuxPids for Linux cgroup 'pids' resource management (Linux 4.3) +type LinuxPids struct { + // Maximum number of PIDs. Default is "no limit". + Limit int64 `json:"limit"` +} + +// LinuxNetwork identification and priority configuration +type LinuxNetwork struct { + // Set class identifier for container's network packets + ClassID *uint32 `json:"classID,omitempty"` + // Set priority of network traffic for container + Priorities []LinuxInterfacePriority `json:"priorities,omitempty"` +} + +// LinuxRdma for Linux cgroup 'rdma' resource management (Linux 4.11) +type LinuxRdma struct { + // Maximum number of HCA handles that can be opened. Default is "no limit". + HcaHandles *uint32 `json:"hcaHandles,omitempty"` + // Maximum number of HCA objects that can be created. Default is "no limit". + HcaObjects *uint32 `json:"hcaObjects,omitempty"` +} + +// LinuxResources has container runtime resource constraints +type LinuxResources struct { + // Devices configures the device allowlist. + Devices []LinuxDeviceCgroup `json:"devices,omitempty"` + // Memory restriction configuration + Memory *LinuxMemory `json:"memory,omitempty"` + // CPU resource restriction configuration + CPU *LinuxCPU `json:"cpu,omitempty"` + // Task resource restriction configuration. + Pids *LinuxPids `json:"pids,omitempty"` + // BlockIO restriction configuration + BlockIO *LinuxBlockIO `json:"blockIO,omitempty"` + // Hugetlb limits (in bytes). Default to reservation limits if supported. + HugepageLimits []LinuxHugepageLimit `json:"hugepageLimits,omitempty"` + // Network restriction configuration + Network *LinuxNetwork `json:"network,omitempty"` + // Rdma resource restriction configuration. + // Limits are a set of key value pairs that define RDMA resource limits, + // where the key is device name and value is resource limits. + Rdma map[string]LinuxRdma `json:"rdma,omitempty"` + // Unified resources. + Unified map[string]string `json:"unified,omitempty"` +} + +// LinuxDevice represents the mknod information for a Linux special device file +type LinuxDevice struct { + // Path to the device. + Path string `json:"path"` + // Device type, block, char, etc. + Type string `json:"type"` + // Major is the device's major number. + Major int64 `json:"major"` + // Minor is the device's minor number. + Minor int64 `json:"minor"` + // FileMode permission bits for the device. + FileMode *os.FileMode `json:"fileMode,omitempty"` + // UID of the device. + UID *uint32 `json:"uid,omitempty"` + // Gid of the device. + GID *uint32 `json:"gid,omitempty"` +} + +// LinuxDeviceCgroup represents a device rule for the devices specified to +// the device controller +type LinuxDeviceCgroup struct { + // Allow or deny + Allow bool `json:"allow"` + // Device type, block, char, etc. + Type string `json:"type,omitempty"` + // Major is the device's major number. + Major *int64 `json:"major,omitempty"` + // Minor is the device's minor number. + Minor *int64 `json:"minor,omitempty"` + // Cgroup access permissions format, rwm. + Access string `json:"access,omitempty"` +} + +// LinuxPersonalityDomain refers to a personality domain. +type LinuxPersonalityDomain string + +// LinuxPersonalityFlag refers to an additional personality flag. None are currently defined. +type LinuxPersonalityFlag string + +// Define domain and flags for Personality +const ( + // PerLinux is the standard Linux personality + PerLinux LinuxPersonalityDomain = "LINUX" + // PerLinux32 sets personality to 32 bit + PerLinux32 LinuxPersonalityDomain = "LINUX32" +) + +// LinuxPersonality represents the Linux personality syscall input +type LinuxPersonality struct { + // Domain for the personality + Domain LinuxPersonalityDomain `json:"domain"` + // Additional flags + Flags []LinuxPersonalityFlag `json:"flags,omitempty"` +} + +// Solaris contains platform-specific configuration for Solaris application containers. +type Solaris struct { + // SMF FMRI which should go "online" before we start the container process. + Milestone string `json:"milestone,omitempty"` + // Maximum set of privileges any process in this container can obtain. + LimitPriv string `json:"limitpriv,omitempty"` + // The maximum amount of shared memory allowed for this container. + MaxShmMemory string `json:"maxShmMemory,omitempty"` + // Specification for automatic creation of network resources for this container. + Anet []SolarisAnet `json:"anet,omitempty"` + // Set limit on the amount of CPU time that can be used by container. + CappedCPU *SolarisCappedCPU `json:"cappedCPU,omitempty"` + // The physical and swap caps on the memory that can be used by this container. + CappedMemory *SolarisCappedMemory `json:"cappedMemory,omitempty"` +} + +// SolarisCappedCPU allows users to set limit on the amount of CPU time that can be used by container. +type SolarisCappedCPU struct { + Ncpus string `json:"ncpus,omitempty"` +} + +// SolarisCappedMemory allows users to set the physical and swap caps on the memory that can be used by this container. +type SolarisCappedMemory struct { + Physical string `json:"physical,omitempty"` + Swap string `json:"swap,omitempty"` +} + +// SolarisAnet provides the specification for automatic creation of network resources for this container. +type SolarisAnet struct { + // Specify a name for the automatically created VNIC datalink. + Linkname string `json:"linkname,omitempty"` + // Specify the link over which the VNIC will be created. + Lowerlink string `json:"lowerLink,omitempty"` + // The set of IP addresses that the container can use. + Allowedaddr string `json:"allowedAddress,omitempty"` + // Specifies whether allowedAddress limitation is to be applied to the VNIC. + Configallowedaddr string `json:"configureAllowedAddress,omitempty"` + // The value of the optional default router. + Defrouter string `json:"defrouter,omitempty"` + // Enable one or more types of link protection. + Linkprotection string `json:"linkProtection,omitempty"` + // Set the VNIC's macAddress + Macaddress string `json:"macAddress,omitempty"` +} + +// Windows defines the runtime configuration for Windows based containers, including Hyper-V containers. +type Windows struct { + // LayerFolders contains a list of absolute paths to directories containing image layers. + LayerFolders []string `json:"layerFolders"` + // Devices are the list of devices to be mapped into the container. + Devices []WindowsDevice `json:"devices,omitempty"` + // Resources contains information for handling resource constraints for the container. + Resources *WindowsResources `json:"resources,omitempty"` + // CredentialSpec contains a JSON object describing a group Managed Service Account (gMSA) specification. + CredentialSpec interface{} `json:"credentialSpec,omitempty"` + // Servicing indicates if the container is being started in a mode to apply a Windows Update servicing operation. + Servicing bool `json:"servicing,omitempty"` + // IgnoreFlushesDuringBoot indicates if the container is being started in a mode where disk writes are not flushed during its boot process. + IgnoreFlushesDuringBoot bool `json:"ignoreFlushesDuringBoot,omitempty"` + // HyperV contains information for running a container with Hyper-V isolation. + HyperV *WindowsHyperV `json:"hyperv,omitempty"` + // Network restriction configuration. + Network *WindowsNetwork `json:"network,omitempty"` +} + +// WindowsDevice represents information about a host device to be mapped into the container. +type WindowsDevice struct { + // Device identifier: interface class GUID, etc. + ID string `json:"id"` + // Device identifier type: "class", etc. + IDType string `json:"idType"` +} + +// WindowsResources has container runtime resource constraints for containers running on Windows. +type WindowsResources struct { + // Memory restriction configuration. + Memory *WindowsMemoryResources `json:"memory,omitempty"` + // CPU resource restriction configuration. + CPU *WindowsCPUResources `json:"cpu,omitempty"` + // Storage restriction configuration. + Storage *WindowsStorageResources `json:"storage,omitempty"` +} + +// WindowsMemoryResources contains memory resource management settings. +type WindowsMemoryResources struct { + // Memory limit in bytes. + Limit *uint64 `json:"limit,omitempty"` +} + +// WindowsCPUResources contains CPU resource management settings. +type WindowsCPUResources struct { + // Count is the number of CPUs available to the container. It represents the + // fraction of the configured processor `count` in a container in relation + // to the processors available in the host. The fraction ultimately + // determines the portion of processor cycles that the threads in a + // container can use during each scheduling interval, as the number of + // cycles per 10,000 cycles. + Count *uint64 `json:"count,omitempty"` + // Shares limits the share of processor time given to the container relative + // to other workloads on the processor. The processor `shares` (`weight` at + // the platform level) is a value between 0 and 10000. + Shares *uint16 `json:"shares,omitempty"` + // Maximum determines the portion of processor cycles that the threads in a + // container can use during each scheduling interval, as the number of + // cycles per 10,000 cycles. Set processor `maximum` to a percentage times + // 100. + Maximum *uint16 `json:"maximum,omitempty"` + // Set of CPUs to affinitize for this container. + Affinity []WindowsCPUGroupAffinity `json:"affinity,omitempty"` +} + +// Similar to _GROUP_AFFINITY struct defined in +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/miniport/ns-miniport-_group_affinity +type WindowsCPUGroupAffinity struct { + // CPU mask relative to this CPU group. + Mask uint64 `json:"mask,omitempty"` + // Processor group the mask refers to, as returned by GetLogicalProcessorInformationEx. + Group uint32 `json:"group,omitempty"` +} + +// WindowsStorageResources contains storage resource management settings. +type WindowsStorageResources struct { + // Specifies maximum Iops for the system drive. + Iops *uint64 `json:"iops,omitempty"` + // Specifies maximum bytes per second for the system drive. + Bps *uint64 `json:"bps,omitempty"` + // Sandbox size specifies the minimum size of the system drive in bytes. + SandboxSize *uint64 `json:"sandboxSize,omitempty"` +} + +// WindowsNetwork contains network settings for Windows containers. +type WindowsNetwork struct { + // List of HNS endpoints that the container should connect to. + EndpointList []string `json:"endpointList,omitempty"` + // Specifies if unqualified DNS name resolution is allowed. + AllowUnqualifiedDNSQuery bool `json:"allowUnqualifiedDNSQuery,omitempty"` + // Comma separated list of DNS suffixes to use for name resolution. + DNSSearchList []string `json:"DNSSearchList,omitempty"` + // Name (ID) of the container that we will share with the network stack. + NetworkSharedContainerName string `json:"networkSharedContainerName,omitempty"` + // name (ID) of the network namespace that will be used for the container. + NetworkNamespace string `json:"networkNamespace,omitempty"` +} + +// WindowsHyperV contains information for configuring a container to run with Hyper-V isolation. +type WindowsHyperV struct { + // UtilityVMPath is an optional path to the image used for the Utility VM. + UtilityVMPath string `json:"utilityVMPath,omitempty"` +} + +// VM contains information for virtual-machine-based containers. +type VM struct { + // Hypervisor specifies hypervisor-related configuration for virtual-machine-based containers. + Hypervisor VMHypervisor `json:"hypervisor,omitempty"` + // Kernel specifies kernel-related configuration for virtual-machine-based containers. + Kernel VMKernel `json:"kernel"` + // Image specifies guest image related configuration for virtual-machine-based containers. + Image VMImage `json:"image,omitempty"` +} + +// VMHypervisor contains information about the hypervisor to use for a virtual machine. +type VMHypervisor struct { + // Path is the host path to the hypervisor used to manage the virtual machine. + Path string `json:"path"` + // Parameters specifies parameters to pass to the hypervisor. + Parameters []string `json:"parameters,omitempty"` +} + +// VMKernel contains information about the kernel to use for a virtual machine. +type VMKernel struct { + // Path is the host path to the kernel used to boot the virtual machine. + Path string `json:"path"` + // Parameters specifies parameters to pass to the kernel. + Parameters []string `json:"parameters,omitempty"` + // InitRD is the host path to an initial ramdisk to be used by the kernel. + InitRD string `json:"initrd,omitempty"` +} + +// VMImage contains information about the virtual machine root image. +type VMImage struct { + // Path is the host path to the root image that the VM kernel would boot into. + Path string `json:"path"` + // Format is the root image format type (e.g. "qcow2", "raw", "vhd", etc). + Format string `json:"format"` +} + +// LinuxSeccomp represents syscall restrictions +type LinuxSeccomp struct { + DefaultAction LinuxSeccompAction `json:"defaultAction"` + DefaultErrnoRet *uint `json:"defaultErrnoRet,omitempty"` + Architectures []Arch `json:"architectures,omitempty"` + Flags []LinuxSeccompFlag `json:"flags,omitempty"` + ListenerPath string `json:"listenerPath,omitempty"` + ListenerMetadata string `json:"listenerMetadata,omitempty"` + Syscalls []LinuxSyscall `json:"syscalls,omitempty"` +} + +// Arch used for additional architectures +type Arch string + +// LinuxSeccompFlag is a flag to pass to seccomp(2). +type LinuxSeccompFlag string + +const ( + // LinuxSeccompFlagLog is a seccomp flag to request all returned + // actions except SECCOMP_RET_ALLOW to be logged. An administrator may + // override this filter flag by preventing specific actions from being + // logged via the /proc/sys/kernel/seccomp/actions_logged file. (since + // Linux 4.14) + LinuxSeccompFlagLog LinuxSeccompFlag = "SECCOMP_FILTER_FLAG_LOG" + + // LinuxSeccompFlagSpecAllow can be used to disable Speculative Store + // Bypass mitigation. (since Linux 4.17) + LinuxSeccompFlagSpecAllow LinuxSeccompFlag = "SECCOMP_FILTER_FLAG_SPEC_ALLOW" + + // LinuxSeccompFlagWaitKillableRecv can be used to switch to the wait + // killable semantics. (since Linux 5.19) + LinuxSeccompFlagWaitKillableRecv LinuxSeccompFlag = "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV" +) + +// Additional architectures permitted to be used for system calls +// By default only the native architecture of the kernel is permitted +const ( + ArchX86 Arch = "SCMP_ARCH_X86" + ArchX86_64 Arch = "SCMP_ARCH_X86_64" + ArchX32 Arch = "SCMP_ARCH_X32" + ArchARM Arch = "SCMP_ARCH_ARM" + ArchAARCH64 Arch = "SCMP_ARCH_AARCH64" + ArchMIPS Arch = "SCMP_ARCH_MIPS" + ArchMIPS64 Arch = "SCMP_ARCH_MIPS64" + ArchMIPS64N32 Arch = "SCMP_ARCH_MIPS64N32" + ArchMIPSEL Arch = "SCMP_ARCH_MIPSEL" + ArchMIPSEL64 Arch = "SCMP_ARCH_MIPSEL64" + ArchMIPSEL64N32 Arch = "SCMP_ARCH_MIPSEL64N32" + ArchPPC Arch = "SCMP_ARCH_PPC" + ArchPPC64 Arch = "SCMP_ARCH_PPC64" + ArchPPC64LE Arch = "SCMP_ARCH_PPC64LE" + ArchS390 Arch = "SCMP_ARCH_S390" + ArchS390X Arch = "SCMP_ARCH_S390X" + ArchPARISC Arch = "SCMP_ARCH_PARISC" + ArchPARISC64 Arch = "SCMP_ARCH_PARISC64" + ArchRISCV64 Arch = "SCMP_ARCH_RISCV64" + ArchLOONGARCH64 Arch = "SCMP_ARCH_LOONGARCH64" + ArchM68K Arch = "SCMP_ARCH_M68K" + ArchSH Arch = "SCMP_ARCH_SH" + ArchSHEB Arch = "SCMP_ARCH_SHEB" +) + +// LinuxSeccompAction taken upon Seccomp rule match +type LinuxSeccompAction string + +// Define actions for Seccomp rules +const ( + ActKill LinuxSeccompAction = "SCMP_ACT_KILL" + ActKillProcess LinuxSeccompAction = "SCMP_ACT_KILL_PROCESS" + ActKillThread LinuxSeccompAction = "SCMP_ACT_KILL_THREAD" + ActTrap LinuxSeccompAction = "SCMP_ACT_TRAP" + ActErrno LinuxSeccompAction = "SCMP_ACT_ERRNO" + ActTrace LinuxSeccompAction = "SCMP_ACT_TRACE" + ActAllow LinuxSeccompAction = "SCMP_ACT_ALLOW" + ActLog LinuxSeccompAction = "SCMP_ACT_LOG" + ActNotify LinuxSeccompAction = "SCMP_ACT_NOTIFY" +) + +// LinuxSeccompOperator used to match syscall arguments in Seccomp +type LinuxSeccompOperator string + +// Define operators for syscall arguments in Seccomp +const ( + OpNotEqual LinuxSeccompOperator = "SCMP_CMP_NE" + OpLessThan LinuxSeccompOperator = "SCMP_CMP_LT" + OpLessEqual LinuxSeccompOperator = "SCMP_CMP_LE" + OpEqualTo LinuxSeccompOperator = "SCMP_CMP_EQ" + OpGreaterEqual LinuxSeccompOperator = "SCMP_CMP_GE" + OpGreaterThan LinuxSeccompOperator = "SCMP_CMP_GT" + OpMaskedEqual LinuxSeccompOperator = "SCMP_CMP_MASKED_EQ" +) + +// LinuxSeccompArg used for matching specific syscall arguments in Seccomp +type LinuxSeccompArg struct { + Index uint `json:"index"` + Value uint64 `json:"value"` + ValueTwo uint64 `json:"valueTwo,omitempty"` + Op LinuxSeccompOperator `json:"op"` +} + +// LinuxSyscall is used to match a syscall in Seccomp +type LinuxSyscall struct { + Names []string `json:"names"` + Action LinuxSeccompAction `json:"action"` + ErrnoRet *uint `json:"errnoRet,omitempty"` + Args []LinuxSeccompArg `json:"args,omitempty"` +} + +// LinuxIntelRdt has container runtime resource constraints for Intel RDT CAT and MBA +// features and flags enabling Intel RDT CMT and MBM features. +// Intel RDT features are available in Linux 4.14 and newer kernel versions. +type LinuxIntelRdt struct { + // The identity for RDT Class of Service + ClosID string `json:"closID,omitempty"` + // The schema for L3 cache id and capacity bitmask (CBM) + // Format: "L3:=;=;..." + L3CacheSchema string `json:"l3CacheSchema,omitempty"` + + // The schema of memory bandwidth per L3 cache id + // Format: "MB:=bandwidth0;=bandwidth1;..." + // The unit of memory bandwidth is specified in "percentages" by + // default, and in "MBps" if MBA Software Controller is enabled. + MemBwSchema string `json:"memBwSchema,omitempty"` + + // EnableCMT is the flag to indicate if the Intel RDT CMT is enabled. CMT (Cache Monitoring Technology) supports monitoring of + // the last-level cache (LLC) occupancy for the container. + EnableCMT bool `json:"enableCMT,omitempty"` + + // EnableMBM is the flag to indicate if the Intel RDT MBM is enabled. MBM (Memory Bandwidth Monitoring) supports monitoring of + // total and local memory bandwidth for the container. + EnableMBM bool `json:"enableMBM,omitempty"` +} + +// ZOS contains platform-specific configuration for z/OS based containers. +type ZOS struct { + // Namespaces contains the namespaces that are created and/or joined by the container + Namespaces []ZOSNamespace `json:"namespaces,omitempty"` +} + +// ZOSNamespace is the configuration for a z/OS namespace +type ZOSNamespace struct { + // Type is the type of namespace + Type ZOSNamespaceType `json:"type"` + // Path is a path to an existing namespace persisted on disk that can be joined + // and is of the same type + Path string `json:"path,omitempty"` +} + +// ZOSNamespaceType is one of the z/OS namespaces +type ZOSNamespaceType string + +const ( + // PIDNamespace for isolating process IDs + ZOSPIDNamespace ZOSNamespaceType = "pid" + // MountNamespace for isolating mount points + ZOSMountNamespace ZOSNamespaceType = "mount" + // IPCNamespace for isolating System V IPC, POSIX message queues + ZOSIPCNamespace ZOSNamespaceType = "ipc" + // UTSNamespace for isolating hostname and NIS domain name + ZOSUTSNamespace ZOSNamespaceType = "uts" +) + +// LinuxSchedulerPolicy represents different scheduling policies used with the Linux Scheduler +type LinuxSchedulerPolicy string + +const ( + // SchedOther is the default scheduling policy + SchedOther LinuxSchedulerPolicy = "SCHED_OTHER" + // SchedFIFO is the First-In-First-Out scheduling policy + SchedFIFO LinuxSchedulerPolicy = "SCHED_FIFO" + // SchedRR is the Round-Robin scheduling policy + SchedRR LinuxSchedulerPolicy = "SCHED_RR" + // SchedBatch is the Batch scheduling policy + SchedBatch LinuxSchedulerPolicy = "SCHED_BATCH" + // SchedISO is the Isolation scheduling policy + SchedISO LinuxSchedulerPolicy = "SCHED_ISO" + // SchedIdle is the Idle scheduling policy + SchedIdle LinuxSchedulerPolicy = "SCHED_IDLE" + // SchedDeadline is the Deadline scheduling policy + SchedDeadline LinuxSchedulerPolicy = "SCHED_DEADLINE" +) + +// LinuxSchedulerFlag represents the flags used by the Linux Scheduler. +type LinuxSchedulerFlag string + +const ( + // SchedFlagResetOnFork represents the reset on fork scheduling flag + SchedFlagResetOnFork LinuxSchedulerFlag = "SCHED_FLAG_RESET_ON_FORK" + // SchedFlagReclaim represents the reclaim scheduling flag + SchedFlagReclaim LinuxSchedulerFlag = "SCHED_FLAG_RECLAIM" + // SchedFlagDLOverrun represents the deadline overrun scheduling flag + SchedFlagDLOverrun LinuxSchedulerFlag = "SCHED_FLAG_DL_OVERRUN" + // SchedFlagKeepPolicy represents the keep policy scheduling flag + SchedFlagKeepPolicy LinuxSchedulerFlag = "SCHED_FLAG_KEEP_POLICY" + // SchedFlagKeepParams represents the keep parameters scheduling flag + SchedFlagKeepParams LinuxSchedulerFlag = "SCHED_FLAG_KEEP_PARAMS" + // SchedFlagUtilClampMin represents the utilization clamp minimum scheduling flag + SchedFlagUtilClampMin LinuxSchedulerFlag = "SCHED_FLAG_UTIL_CLAMP_MIN" + // SchedFlagUtilClampMin represents the utilization clamp maximum scheduling flag + SchedFlagUtilClampMax LinuxSchedulerFlag = "SCHED_FLAG_UTIL_CLAMP_MAX" +) diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go new file mode 100644 index 00000000..7c010d4f --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go @@ -0,0 +1,56 @@ +package specs + +// ContainerState represents the state of a container. +type ContainerState string + +const ( + // StateCreating indicates that the container is being created + StateCreating ContainerState = "creating" + + // StateCreated indicates that the runtime has finished the create operation + StateCreated ContainerState = "created" + + // StateRunning indicates that the container process has executed the + // user-specified program but has not exited + StateRunning ContainerState = "running" + + // StateStopped indicates that the container process has exited + StateStopped ContainerState = "stopped" +) + +// State holds information about the runtime state of the container. +type State struct { + // Version is the version of the specification that is supported. + Version string `json:"ociVersion"` + // ID is the container ID + ID string `json:"id"` + // Status is the runtime status of the container. + Status ContainerState `json:"status"` + // Pid is the process ID for the container process. + Pid int `json:"pid,omitempty"` + // Bundle is the path to the container's bundle directory. + Bundle string `json:"bundle"` + // Annotations are key values associated with the container. + Annotations map[string]string `json:"annotations,omitempty"` +} + +const ( + // SeccompFdName is the name of the seccomp notify file descriptor. + SeccompFdName string = "seccompFd" +) + +// ContainerProcessState holds information about the state of a container process. +type ContainerProcessState struct { + // Version is the version of the specification that is supported. + Version string `json:"ociVersion"` + // Fds is a string array containing the names of the file descriptors passed. + // The index of the name in this array corresponds to index of the file + // descriptor in the `SCM_RIGHTS` array. + Fds []string `json:"fds"` + // Pid is the process ID as seen by the runtime. + Pid int `json:"pid"` + // Opaque metadata. + Metadata string `json:"metadata,omitempty"` + // State of the container. + State State `json:"state"` +} diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go new file mode 100644 index 00000000..23234a9c --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go @@ -0,0 +1,18 @@ +package specs + +import "fmt" + +const ( + // VersionMajor is for an API incompatible changes + VersionMajor = 1 + // VersionMinor is for functionality in a backwards-compatible manner + VersionMinor = 2 + // VersionPatch is for backwards-compatible bug fixes + VersionPatch = 1 + + // VersionDev indicates development branch. Releases will be empty string. + VersionDev = "" +) + +// Version is the specification version that the package types support. +var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev) diff --git a/vendor/github.com/opencontainers/runtime-tools/LICENSE b/vendor/github.com/opencontainers/runtime-tools/LICENSE new file mode 100644 index 00000000..bdc40365 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor 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, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 The Linux Foundation. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/config.go b/vendor/github.com/opencontainers/runtime-tools/generate/config.go new file mode 100644 index 00000000..48f281d2 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/config.go @@ -0,0 +1,194 @@ +package generate + +import ( + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +func (g *Generator) initConfig() { + if g.Config == nil { + g.Config = &rspec.Spec{} + } +} + +func (g *Generator) initConfigProcess() { + g.initConfig() + if g.Config.Process == nil { + g.Config.Process = &rspec.Process{} + } +} + +func (g *Generator) initConfigProcessConsoleSize() { + g.initConfigProcess() + if g.Config.Process.ConsoleSize == nil { + g.Config.Process.ConsoleSize = &rspec.Box{} + } +} + +func (g *Generator) initConfigProcessCapabilities() { + g.initConfigProcess() + if g.Config.Process.Capabilities == nil { + g.Config.Process.Capabilities = &rspec.LinuxCapabilities{} + } +} + +func (g *Generator) initConfigRoot() { + g.initConfig() + if g.Config.Root == nil { + g.Config.Root = &rspec.Root{} + } +} + +func (g *Generator) initConfigAnnotations() { + g.initConfig() + if g.Config.Annotations == nil { + g.Config.Annotations = make(map[string]string) + } +} + +func (g *Generator) initConfigHooks() { + g.initConfig() + if g.Config.Hooks == nil { + g.Config.Hooks = &rspec.Hooks{} + } +} + +func (g *Generator) initConfigLinux() { + g.initConfig() + if g.Config.Linux == nil { + g.Config.Linux = &rspec.Linux{} + } +} + +func (g *Generator) initConfigLinuxIntelRdt() { + g.initConfigLinux() + if g.Config.Linux.IntelRdt == nil { + g.Config.Linux.IntelRdt = &rspec.LinuxIntelRdt{} + } +} + +func (g *Generator) initConfigLinuxSysctl() { + g.initConfigLinux() + if g.Config.Linux.Sysctl == nil { + g.Config.Linux.Sysctl = make(map[string]string) + } +} + +func (g *Generator) initConfigLinuxSeccomp() { + g.initConfigLinux() + if g.Config.Linux.Seccomp == nil { + g.Config.Linux.Seccomp = &rspec.LinuxSeccomp{} + } +} + +func (g *Generator) initConfigLinuxResources() { + g.initConfigLinux() + if g.Config.Linux.Resources == nil { + g.Config.Linux.Resources = &rspec.LinuxResources{} + } +} + +func (g *Generator) initConfigLinuxResourcesBlockIO() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.BlockIO == nil { + g.Config.Linux.Resources.BlockIO = &rspec.LinuxBlockIO{} + } +} + +// InitConfigLinuxResourcesCPU initializes CPU of Linux resources +func (g *Generator) InitConfigLinuxResourcesCPU() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.CPU == nil { + g.Config.Linux.Resources.CPU = &rspec.LinuxCPU{} + } +} + +func (g *Generator) initConfigLinuxResourcesMemory() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.Memory == nil { + g.Config.Linux.Resources.Memory = &rspec.LinuxMemory{} + } +} + +func (g *Generator) initConfigLinuxResourcesNetwork() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.Network == nil { + g.Config.Linux.Resources.Network = &rspec.LinuxNetwork{} + } +} + +func (g *Generator) initConfigLinuxResourcesPids() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.Pids == nil { + g.Config.Linux.Resources.Pids = &rspec.LinuxPids{} + } +} + +func (g *Generator) initConfigLinuxResourcesUnified() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.Unified == nil { + g.Config.Linux.Resources.Unified = map[string]string{} + } +} + +func (g *Generator) initConfigSolaris() { + g.initConfig() + if g.Config.Solaris == nil { + g.Config.Solaris = &rspec.Solaris{} + } +} + +func (g *Generator) initConfigSolarisCappedCPU() { + g.initConfigSolaris() + if g.Config.Solaris.CappedCPU == nil { + g.Config.Solaris.CappedCPU = &rspec.SolarisCappedCPU{} + } +} + +func (g *Generator) initConfigSolarisCappedMemory() { + g.initConfigSolaris() + if g.Config.Solaris.CappedMemory == nil { + g.Config.Solaris.CappedMemory = &rspec.SolarisCappedMemory{} + } +} + +func (g *Generator) initConfigWindows() { + g.initConfig() + if g.Config.Windows == nil { + g.Config.Windows = &rspec.Windows{} + } +} + +func (g *Generator) initConfigWindowsNetwork() { + g.initConfigWindows() + if g.Config.Windows.Network == nil { + g.Config.Windows.Network = &rspec.WindowsNetwork{} + } +} + +func (g *Generator) initConfigWindowsHyperV() { + g.initConfigWindows() + if g.Config.Windows.HyperV == nil { + g.Config.Windows.HyperV = &rspec.WindowsHyperV{} + } +} + +func (g *Generator) initConfigWindowsResources() { + g.initConfigWindows() + if g.Config.Windows.Resources == nil { + g.Config.Windows.Resources = &rspec.WindowsResources{} + } +} + +func (g *Generator) initConfigWindowsResourcesMemory() { + g.initConfigWindowsResources() + if g.Config.Windows.Resources.Memory == nil { + g.Config.Windows.Resources.Memory = &rspec.WindowsMemoryResources{} + } +} + +func (g *Generator) initConfigVM() { + g.initConfig() + if g.Config.VM == nil { + g.Config.VM = &rspec.VM{} + } +} diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/generate.go b/vendor/github.com/opencontainers/runtime-tools/generate/generate.go new file mode 100644 index 00000000..4d66b320 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/generate.go @@ -0,0 +1,1874 @@ +// Package generate implements functions generating container config files. +package generate + +import ( + "encoding/json" + "fmt" + "io" + "os" + "strings" + + rspec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-tools/generate/seccomp" + capsCheck "github.com/opencontainers/runtime-tools/validate/capabilities" + "github.com/syndtr/gocapability/capability" +) + +var ( + // Namespaces include the names of supported namespaces. + Namespaces = []string{"network", "pid", "mount", "ipc", "uts", "user", "cgroup"} + + // we don't care about order...and this is way faster... + removeFunc = func(s []string, i int) []string { + s[i] = s[len(s)-1] + return s[:len(s)-1] + } +) + +// Generator represents a generator for a container config. +type Generator struct { + Config *rspec.Spec + HostSpecific bool + // This is used to keep a cache of the ENVs added to improve + // performance when adding a huge number of ENV variables + envMap map[string]int +} + +// ExportOptions have toggles for exporting only certain parts of the specification +type ExportOptions struct { + Seccomp bool // seccomp toggles if only seccomp should be exported +} + +// New creates a configuration Generator with the default +// configuration for the target operating system. +func New(os string) (generator Generator, err error) { + if os != "linux" && os != "solaris" && os != "windows" && os != "freebsd" { + return generator, fmt.Errorf("no defaults configured for %s", os) + } + + config := rspec.Spec{ + Version: rspec.Version, + Hostname: "mrsdalloway", + } + + if os == "windows" { + config.Process = &rspec.Process{ + Args: []string{ + "cmd", + }, + Cwd: `C:\`, + } + config.Windows = &rspec.Windows{} + } else { + config.Root = &rspec.Root{ + Path: "rootfs", + Readonly: false, + } + config.Process = &rspec.Process{ + Terminal: false, + Args: []string{ + "sh", + }, + } + } + + if os == "linux" || os == "solaris" || os == "freebsd" { + config.Process.User = rspec.User{} + config.Process.Env = []string{ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm", + } + config.Process.Cwd = "/" + config.Process.Rlimits = []rspec.POSIXRlimit{ + { + Type: "RLIMIT_NOFILE", + Hard: uint64(1024), + Soft: uint64(1024), + }, + } + } + + if os == "linux" { + config.Process.Capabilities = &rspec.LinuxCapabilities{ + Bounding: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Permitted: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Inheritable: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Effective: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Ambient: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + } + config.Mounts = []rspec.Mount{ + { + Destination: "/proc", + Type: "proc", + Source: "proc", + Options: []string{"nosuid", "noexec", "nodev"}, + }, + { + Destination: "/dev", + Type: "tmpfs", + Source: "tmpfs", + Options: []string{"nosuid", "noexec", "strictatime", "mode=755", "size=65536k"}, + }, + { + Destination: "/dev/pts", + Type: "devpts", + Source: "devpts", + Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"}, + }, + { + Destination: "/dev/shm", + Type: "tmpfs", + Source: "shm", + Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"}, + }, + { + Destination: "/dev/mqueue", + Type: "mqueue", + Source: "mqueue", + Options: []string{"nosuid", "noexec", "nodev"}, + }, + { + Destination: "/sys", + Type: "sysfs", + Source: "sysfs", + Options: []string{"nosuid", "noexec", "nodev", "ro"}, + }, + } + config.Linux = &rspec.Linux{ + Resources: &rspec.LinuxResources{ + Devices: []rspec.LinuxDeviceCgroup{ + { + Allow: false, + Access: "rwm", + }, + }, + }, + Namespaces: []rspec.LinuxNamespace{ + { + Type: "pid", + }, + { + Type: "network", + }, + { + Type: "ipc", + }, + { + Type: "uts", + }, + { + Type: "mount", + }, + }, + Seccomp: seccomp.DefaultProfile(&config), + } + } else if os == "freebsd" { + config.Mounts = []rspec.Mount{ + { + Destination: "/dev", + Type: "devfs", + Source: "devfs", + Options: []string{"ruleset=4"}, + }, + { + Destination: "/dev/fd", + Type: "fdescfs", + Source: "fdesc", + Options: []string{}, + }, + } + } + + envCache := map[string]int{} + if config.Process != nil { + envCache = createEnvCacheMap(config.Process.Env) + } + + return Generator{Config: &config, envMap: envCache}, nil +} + +// NewFromSpec creates a configuration Generator from a given +// configuration. +func NewFromSpec(config *rspec.Spec) Generator { + envCache := map[string]int{} + if config != nil && config.Process != nil { + envCache = createEnvCacheMap(config.Process.Env) + } + + return Generator{ + Config: config, + envMap: envCache, + } +} + +// NewFromFile loads the template specified in a file into a +// configuration Generator. +func NewFromFile(path string) (Generator, error) { + cf, err := os.Open(path) + if err != nil { + if os.IsNotExist(err) { + return Generator{}, fmt.Errorf("template configuration at %s not found", path) + } + return Generator{}, err + } + defer cf.Close() + + return NewFromTemplate(cf) +} + +// NewFromTemplate loads the template from io.Reader into a +// configuration Generator. +func NewFromTemplate(r io.Reader) (Generator, error) { + var config rspec.Spec + if err := json.NewDecoder(r).Decode(&config); err != nil { + return Generator{}, err + } + + envCache := map[string]int{} + if config.Process != nil { + envCache = createEnvCacheMap(config.Process.Env) + } + + return Generator{ + Config: &config, + envMap: envCache, + }, nil +} + +// createEnvCacheMap creates a hash map with the ENV variables given by the config +func createEnvCacheMap(env []string) map[string]int { + envMap := make(map[string]int, len(env)) + for i, val := range env { + envMap[val] = i + } + return envMap +} + +// SetSpec sets the configuration in the Generator g. +// +// Deprecated: Replace with: +// +// Use generator.Config = config +func (g *Generator) SetSpec(config *rspec.Spec) { + g.Config = config +} + +// Spec gets the configuration from the Generator g. +// +// Deprecated: Replace with generator.Config. +func (g *Generator) Spec() *rspec.Spec { + return g.Config +} + +// Save writes the configuration into w. +func (g *Generator) Save(w io.Writer, exportOpts ExportOptions) (err error) { + var data []byte + + if g.Config.Linux != nil { + buf, err := json.Marshal(g.Config.Linux) + if err != nil { + return err + } + if string(buf) == "{}" { + g.Config.Linux = nil + } + } + + if exportOpts.Seccomp { + data, err = json.MarshalIndent(g.Config.Linux.Seccomp, "", "\t") + } else { + data, err = json.MarshalIndent(g.Config, "", "\t") + } + if err != nil { + return err + } + + _, err = w.Write(data) + if err != nil { + return err + } + + return nil +} + +// SaveToFile writes the configuration into a file. +func (g *Generator) SaveToFile(path string, exportOpts ExportOptions) error { + f, err := os.Create(path) + if err != nil { + return err + } + defer f.Close() + return g.Save(f, exportOpts) +} + +// SetVersion sets g.Config.Version. +func (g *Generator) SetVersion(version string) { + g.initConfig() + g.Config.Version = version +} + +// SetRootPath sets g.Config.Root.Path. +func (g *Generator) SetRootPath(path string) { + g.initConfigRoot() + g.Config.Root.Path = path +} + +// SetRootReadonly sets g.Config.Root.Readonly. +func (g *Generator) SetRootReadonly(b bool) { + g.initConfigRoot() + g.Config.Root.Readonly = b +} + +// SetHostname sets g.Config.Hostname. +func (g *Generator) SetHostname(s string) { + g.initConfig() + g.Config.Hostname = s +} + +// SetOCIVersion sets g.Config.Version. +func (g *Generator) SetOCIVersion(s string) { + g.initConfig() + g.Config.Version = s +} + +// ClearAnnotations clears g.Config.Annotations. +func (g *Generator) ClearAnnotations() { + if g.Config == nil { + return + } + g.Config.Annotations = make(map[string]string) +} + +// AddAnnotation adds an annotation into g.Config.Annotations. +func (g *Generator) AddAnnotation(key, value string) { + g.initConfigAnnotations() + g.Config.Annotations[key] = value +} + +// RemoveAnnotation remove an annotation from g.Config.Annotations. +func (g *Generator) RemoveAnnotation(key string) { + if g.Config == nil || g.Config.Annotations == nil { + return + } + delete(g.Config.Annotations, key) +} + +// RemoveHostname removes g.Config.Hostname, setting it to an empty string. +func (g *Generator) RemoveHostname() { + if g.Config == nil { + return + } + g.Config.Hostname = "" +} + +// SetProcessConsoleSize sets g.Config.Process.ConsoleSize. +func (g *Generator) SetProcessConsoleSize(width, height uint) { + g.initConfigProcessConsoleSize() + g.Config.Process.ConsoleSize.Width = width + g.Config.Process.ConsoleSize.Height = height +} + +// SetProcessUID sets g.Config.Process.User.UID. +func (g *Generator) SetProcessUID(uid uint32) { + g.initConfigProcess() + g.Config.Process.User.UID = uid +} + +// SetProcessUsername sets g.Config.Process.User.Username. +func (g *Generator) SetProcessUsername(username string) { + g.initConfigProcess() + g.Config.Process.User.Username = username +} + +// SetProcessUmask sets g.Config.Process.User.Umask. +func (g *Generator) SetProcessUmask(umask uint32) { + g.initConfigProcess() + u := umask + g.Config.Process.User.Umask = &u +} + +// SetProcessGID sets g.Config.Process.User.GID. +func (g *Generator) SetProcessGID(gid uint32) { + g.initConfigProcess() + g.Config.Process.User.GID = gid +} + +// SetProcessCwd sets g.Config.Process.Cwd. +func (g *Generator) SetProcessCwd(cwd string) { + g.initConfigProcess() + g.Config.Process.Cwd = cwd +} + +// SetProcessNoNewPrivileges sets g.Config.Process.NoNewPrivileges. +func (g *Generator) SetProcessNoNewPrivileges(b bool) { + g.initConfigProcess() + g.Config.Process.NoNewPrivileges = b +} + +// SetProcessTerminal sets g.Config.Process.Terminal. +func (g *Generator) SetProcessTerminal(b bool) { + g.initConfigProcess() + g.Config.Process.Terminal = b +} + +// SetProcessApparmorProfile sets g.Config.Process.ApparmorProfile. +func (g *Generator) SetProcessApparmorProfile(prof string) { + g.initConfigProcess() + g.Config.Process.ApparmorProfile = prof +} + +// SetProcessArgs sets g.Config.Process.Args. +func (g *Generator) SetProcessArgs(args []string) { + g.initConfigProcess() + g.Config.Process.Args = args +} + +// ClearProcessEnv clears g.Config.Process.Env. +func (g *Generator) ClearProcessEnv() { + if g.Config == nil || g.Config.Process == nil { + return + } + g.Config.Process.Env = []string{} + // Clear out the env cache map as well + g.envMap = map[string]int{} +} + +// AddProcessEnv adds name=value into g.Config.Process.Env, or replaces an +// existing entry with the given name. +func (g *Generator) AddProcessEnv(name, value string) { + if name == "" { + return + } + + g.initConfigProcess() + g.addEnv(fmt.Sprintf("%s=%s", name, value), name) +} + +// AddMultipleProcessEnv adds multiple name=value into g.Config.Process.Env, or replaces +// existing entries with the given name. +func (g *Generator) AddMultipleProcessEnv(envs []string) { + g.initConfigProcess() + + for _, val := range envs { + split := strings.SplitN(val, "=", 2) + g.addEnv(val, split[0]) + } +} + +// addEnv looks through adds ENV to the Process and checks envMap for +// any duplicates +// This is called by both AddMultipleProcessEnv and AddProcessEnv +func (g *Generator) addEnv(env, key string) { + if idx, ok := g.envMap[key]; ok { + // The ENV exists in the cache, so change its value in g.Config.Process.Env + g.Config.Process.Env[idx] = env + } else { + // else the env doesn't exist, so add it and add it's index to g.envMap + g.Config.Process.Env = append(g.Config.Process.Env, env) + g.envMap[key] = len(g.Config.Process.Env) - 1 + } +} + +// AddProcessRlimits adds rlimit into g.Config.Process.Rlimits. +func (g *Generator) AddProcessRlimits(rType string, rHard uint64, rSoft uint64) { + g.initConfigProcess() + for i, rlimit := range g.Config.Process.Rlimits { + if rlimit.Type == rType { + g.Config.Process.Rlimits[i].Hard = rHard + g.Config.Process.Rlimits[i].Soft = rSoft + return + } + } + + newRlimit := rspec.POSIXRlimit{ + Type: rType, + Hard: rHard, + Soft: rSoft, + } + g.Config.Process.Rlimits = append(g.Config.Process.Rlimits, newRlimit) +} + +// RemoveProcessRlimits removes a rlimit from g.Config.Process.Rlimits. +func (g *Generator) RemoveProcessRlimits(rType string) { + if g.Config == nil || g.Config.Process == nil { + return + } + for i, rlimit := range g.Config.Process.Rlimits { + if rlimit.Type == rType { + g.Config.Process.Rlimits = append(g.Config.Process.Rlimits[:i], g.Config.Process.Rlimits[i+1:]...) + return + } + } +} + +// ClearProcessRlimits clear g.Config.Process.Rlimits. +func (g *Generator) ClearProcessRlimits() { + if g.Config == nil || g.Config.Process == nil { + return + } + g.Config.Process.Rlimits = []rspec.POSIXRlimit{} +} + +// ClearProcessAdditionalGids clear g.Config.Process.AdditionalGids. +func (g *Generator) ClearProcessAdditionalGids() { + if g.Config == nil || g.Config.Process == nil { + return + } + g.Config.Process.User.AdditionalGids = []uint32{} +} + +// AddProcessAdditionalGid adds an additional gid into g.Config.Process.AdditionalGids. +func (g *Generator) AddProcessAdditionalGid(gid uint32) { + g.initConfigProcess() + for _, group := range g.Config.Process.User.AdditionalGids { + if group == gid { + return + } + } + g.Config.Process.User.AdditionalGids = append(g.Config.Process.User.AdditionalGids, gid) +} + +// SetProcessSelinuxLabel sets g.Config.Process.SelinuxLabel. +func (g *Generator) SetProcessSelinuxLabel(label string) { + g.initConfigProcess() + g.Config.Process.SelinuxLabel = label +} + +// SetLinuxCgroupsPath sets g.Config.Linux.CgroupsPath. +func (g *Generator) SetLinuxCgroupsPath(path string) { + g.initConfigLinux() + g.Config.Linux.CgroupsPath = path +} + +// SetLinuxIntelRdtClosID sets g.Config.Linux.IntelRdt.ClosID +func (g *Generator) SetLinuxIntelRdtClosID(clos string) { + g.initConfigLinuxIntelRdt() + g.Config.Linux.IntelRdt.ClosID = clos +} + +// SetLinuxIntelRdtL3CacheSchema sets g.Config.Linux.IntelRdt.L3CacheSchema +func (g *Generator) SetLinuxIntelRdtL3CacheSchema(schema string) { + g.initConfigLinuxIntelRdt() + g.Config.Linux.IntelRdt.L3CacheSchema = schema +} + +// SetLinuxMountLabel sets g.Config.Linux.MountLabel. +func (g *Generator) SetLinuxMountLabel(label string) { + g.initConfigLinux() + g.Config.Linux.MountLabel = label +} + +// SetProcessOOMScoreAdj sets g.Config.Process.OOMScoreAdj. +func (g *Generator) SetProcessOOMScoreAdj(adj int) { + g.initConfigProcess() + g.Config.Process.OOMScoreAdj = &adj +} + +// SetLinuxResourcesBlockIOLeafWeight sets g.Config.Linux.Resources.BlockIO.LeafWeight. +func (g *Generator) SetLinuxResourcesBlockIOLeafWeight(weight uint16) { + g.initConfigLinuxResourcesBlockIO() + g.Config.Linux.Resources.BlockIO.LeafWeight = &weight +} + +// AddLinuxResourcesBlockIOLeafWeightDevice adds or sets g.Config.Linux.Resources.BlockIO.WeightDevice.LeafWeight. +func (g *Generator) AddLinuxResourcesBlockIOLeafWeightDevice(major int64, minor int64, weight uint16) { + g.initConfigLinuxResourcesBlockIO() + for i, weightDevice := range g.Config.Linux.Resources.BlockIO.WeightDevice { + if weightDevice.Major == major && weightDevice.Minor == minor { + g.Config.Linux.Resources.BlockIO.WeightDevice[i].LeafWeight = &weight + return + } + } + weightDevice := new(rspec.LinuxWeightDevice) + weightDevice.Major = major + weightDevice.Minor = minor + weightDevice.LeafWeight = &weight + g.Config.Linux.Resources.BlockIO.WeightDevice = append(g.Config.Linux.Resources.BlockIO.WeightDevice, *weightDevice) +} + +// DropLinuxResourcesBlockIOLeafWeightDevice drops a item form g.Config.Linux.Resources.BlockIO.WeightDevice.LeafWeight +func (g *Generator) DropLinuxResourcesBlockIOLeafWeightDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + for i, weightDevice := range g.Config.Linux.Resources.BlockIO.WeightDevice { + if weightDevice.Major == major && weightDevice.Minor == minor { + if weightDevice.Weight != nil { + newWeightDevice := new(rspec.LinuxWeightDevice) + newWeightDevice.Major = major + newWeightDevice.Minor = minor + newWeightDevice.Weight = weightDevice.Weight + g.Config.Linux.Resources.BlockIO.WeightDevice[i] = *newWeightDevice + } else { + g.Config.Linux.Resources.BlockIO.WeightDevice = append(g.Config.Linux.Resources.BlockIO.WeightDevice[:i], g.Config.Linux.Resources.BlockIO.WeightDevice[i+1:]...) + } + return + } + } +} + +// SetLinuxResourcesBlockIOWeight sets g.Config.Linux.Resources.BlockIO.Weight. +func (g *Generator) SetLinuxResourcesBlockIOWeight(weight uint16) { + g.initConfigLinuxResourcesBlockIO() + g.Config.Linux.Resources.BlockIO.Weight = &weight +} + +// AddLinuxResourcesBlockIOWeightDevice adds or sets g.Config.Linux.Resources.BlockIO.WeightDevice.Weight. +func (g *Generator) AddLinuxResourcesBlockIOWeightDevice(major int64, minor int64, weight uint16) { + g.initConfigLinuxResourcesBlockIO() + for i, weightDevice := range g.Config.Linux.Resources.BlockIO.WeightDevice { + if weightDevice.Major == major && weightDevice.Minor == minor { + g.Config.Linux.Resources.BlockIO.WeightDevice[i].Weight = &weight + return + } + } + weightDevice := new(rspec.LinuxWeightDevice) + weightDevice.Major = major + weightDevice.Minor = minor + weightDevice.Weight = &weight + g.Config.Linux.Resources.BlockIO.WeightDevice = append(g.Config.Linux.Resources.BlockIO.WeightDevice, *weightDevice) +} + +// DropLinuxResourcesBlockIOWeightDevice drops a item form g.Config.Linux.Resources.BlockIO.WeightDevice.Weight +func (g *Generator) DropLinuxResourcesBlockIOWeightDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + for i, weightDevice := range g.Config.Linux.Resources.BlockIO.WeightDevice { + if weightDevice.Major == major && weightDevice.Minor == minor { + if weightDevice.LeafWeight != nil { + newWeightDevice := new(rspec.LinuxWeightDevice) + newWeightDevice.Major = major + newWeightDevice.Minor = minor + newWeightDevice.LeafWeight = weightDevice.LeafWeight + g.Config.Linux.Resources.BlockIO.WeightDevice[i] = *newWeightDevice + } else { + g.Config.Linux.Resources.BlockIO.WeightDevice = append(g.Config.Linux.Resources.BlockIO.WeightDevice[:i], g.Config.Linux.Resources.BlockIO.WeightDevice[i+1:]...) + } + return + } + } +} + +// AddLinuxResourcesBlockIOThrottleReadBpsDevice adds or sets g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice. +func (g *Generator) AddLinuxResourcesBlockIOThrottleReadBpsDevice(major int64, minor int64, rate uint64) { + g.initConfigLinuxResourcesBlockIO() + throttleDevices := addOrReplaceBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice, major, minor, rate) + g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice = throttleDevices +} + +// DropLinuxResourcesBlockIOThrottleReadBpsDevice drops a item from g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice. +func (g *Generator) DropLinuxResourcesBlockIOThrottleReadBpsDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + throttleDevices := dropBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice, major, minor) + g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice = throttleDevices +} + +// AddLinuxResourcesBlockIOThrottleReadIOPSDevice adds or sets g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice. +func (g *Generator) AddLinuxResourcesBlockIOThrottleReadIOPSDevice(major int64, minor int64, rate uint64) { + g.initConfigLinuxResourcesBlockIO() + throttleDevices := addOrReplaceBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice, major, minor, rate) + g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice = throttleDevices +} + +// DropLinuxResourcesBlockIOThrottleReadIOPSDevice drops a item from g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice. +func (g *Generator) DropLinuxResourcesBlockIOThrottleReadIOPSDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + throttleDevices := dropBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice, major, minor) + g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice = throttleDevices +} + +// AddLinuxResourcesBlockIOThrottleWriteBpsDevice adds or sets g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice. +func (g *Generator) AddLinuxResourcesBlockIOThrottleWriteBpsDevice(major int64, minor int64, rate uint64) { + g.initConfigLinuxResourcesBlockIO() + throttleDevices := addOrReplaceBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice, major, minor, rate) + g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice = throttleDevices +} + +// DropLinuxResourcesBlockIOThrottleWriteBpsDevice drops a item from g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice. +func (g *Generator) DropLinuxResourcesBlockIOThrottleWriteBpsDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + throttleDevices := dropBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice, major, minor) + g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice = throttleDevices +} + +// AddLinuxResourcesBlockIOThrottleWriteIOPSDevice adds or sets g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice. +func (g *Generator) AddLinuxResourcesBlockIOThrottleWriteIOPSDevice(major int64, minor int64, rate uint64) { + g.initConfigLinuxResourcesBlockIO() + throttleDevices := addOrReplaceBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice, major, minor, rate) + g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice = throttleDevices +} + +// DropLinuxResourcesBlockIOThrottleWriteIOPSDevice drops a item from g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice. +func (g *Generator) DropLinuxResourcesBlockIOThrottleWriteIOPSDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + throttleDevices := dropBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice, major, minor) + g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice = throttleDevices +} + +// SetLinuxResourcesCPUShares sets g.Config.Linux.Resources.CPU.Shares. +func (g *Generator) SetLinuxResourcesCPUShares(shares uint64) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.Shares = &shares +} + +// SetLinuxResourcesCPUQuota sets g.Config.Linux.Resources.CPU.Quota. +func (g *Generator) SetLinuxResourcesCPUQuota(quota int64) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.Quota = "a +} + +// SetLinuxResourcesCPUPeriod sets g.Config.Linux.Resources.CPU.Period. +func (g *Generator) SetLinuxResourcesCPUPeriod(period uint64) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.Period = &period +} + +// SetLinuxResourcesCPURealtimeRuntime sets g.Config.Linux.Resources.CPU.RealtimeRuntime. +func (g *Generator) SetLinuxResourcesCPURealtimeRuntime(time int64) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.RealtimeRuntime = &time +} + +// SetLinuxResourcesCPURealtimePeriod sets g.Config.Linux.Resources.CPU.RealtimePeriod. +func (g *Generator) SetLinuxResourcesCPURealtimePeriod(period uint64) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.RealtimePeriod = &period +} + +// SetLinuxResourcesCPUCpus sets g.Config.Linux.Resources.CPU.Cpus. +func (g *Generator) SetLinuxResourcesCPUCpus(cpus string) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.Cpus = cpus +} + +// SetLinuxResourcesCPUMems sets g.Config.Linux.Resources.CPU.Mems. +func (g *Generator) SetLinuxResourcesCPUMems(mems string) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.Mems = mems +} + +// AddLinuxResourcesHugepageLimit adds or sets g.Config.Linux.Resources.HugepageLimits. +func (g *Generator) AddLinuxResourcesHugepageLimit(pageSize string, limit uint64) { + hugepageLimit := rspec.LinuxHugepageLimit{ + Pagesize: pageSize, + Limit: limit, + } + + g.initConfigLinuxResources() + for i, pageLimit := range g.Config.Linux.Resources.HugepageLimits { + if pageLimit.Pagesize == pageSize { + g.Config.Linux.Resources.HugepageLimits[i].Limit = limit + return + } + } + g.Config.Linux.Resources.HugepageLimits = append(g.Config.Linux.Resources.HugepageLimits, hugepageLimit) +} + +// DropLinuxResourcesHugepageLimit drops a hugepage limit from g.Config.Linux.Resources.HugepageLimits. +func (g *Generator) DropLinuxResourcesHugepageLimit(pageSize string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil { + return + } + + for i, pageLimit := range g.Config.Linux.Resources.HugepageLimits { + if pageLimit.Pagesize == pageSize { + g.Config.Linux.Resources.HugepageLimits = append(g.Config.Linux.Resources.HugepageLimits[:i], g.Config.Linux.Resources.HugepageLimits[i+1:]...) + return + } + } +} + +// AddLinuxResourcesUnified sets the g.Config.Linux.Resources.Unified +func (g *Generator) SetLinuxResourcesUnified(unified map[string]string) { + g.initConfigLinuxResourcesUnified() + for k, v := range unified { + g.Config.Linux.Resources.Unified[k] = v + } +} + +// AddLinuxResourcesUnified adds or updates the key-value pair from g.Config.Linux.Resources.Unified +func (g *Generator) AddLinuxResourcesUnified(key, val string) { + g.initConfigLinuxResourcesUnified() + g.Config.Linux.Resources.Unified[key] = val +} + +// DropLinuxResourcesUnified drops a key-value pair from g.Config.Linux.Resources.Unified +func (g *Generator) DropLinuxResourcesUnified(key string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.Unified == nil { + return + } + delete(g.Config.Linux.Resources.Unified, key) +} + +// SetLinuxResourcesMemoryLimit sets g.Config.Linux.Resources.Memory.Limit. +func (g *Generator) SetLinuxResourcesMemoryLimit(limit int64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.Limit = &limit +} + +// SetLinuxResourcesMemoryReservation sets g.Config.Linux.Resources.Memory.Reservation. +func (g *Generator) SetLinuxResourcesMemoryReservation(reservation int64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.Reservation = &reservation +} + +// SetLinuxResourcesMemorySwap sets g.Config.Linux.Resources.Memory.Swap. +func (g *Generator) SetLinuxResourcesMemorySwap(swap int64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.Swap = &swap +} + +// SetLinuxResourcesMemoryKernel sets g.Config.Linux.Resources.Memory.Kernel. +func (g *Generator) SetLinuxResourcesMemoryKernel(kernel int64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.Kernel = &kernel +} + +// SetLinuxResourcesMemoryKernelTCP sets g.Config.Linux.Resources.Memory.KernelTCP. +func (g *Generator) SetLinuxResourcesMemoryKernelTCP(kernelTCP int64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.KernelTCP = &kernelTCP +} + +// SetLinuxResourcesMemorySwappiness sets g.Config.Linux.Resources.Memory.Swappiness. +func (g *Generator) SetLinuxResourcesMemorySwappiness(swappiness uint64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.Swappiness = &swappiness +} + +// SetLinuxResourcesMemoryDisableOOMKiller sets g.Config.Linux.Resources.Memory.DisableOOMKiller. +func (g *Generator) SetLinuxResourcesMemoryDisableOOMKiller(disable bool) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.DisableOOMKiller = &disable +} + +// SetLinuxResourcesNetworkClassID sets g.Config.Linux.Resources.Network.ClassID. +func (g *Generator) SetLinuxResourcesNetworkClassID(classid uint32) { + g.initConfigLinuxResourcesNetwork() + g.Config.Linux.Resources.Network.ClassID = &classid +} + +// AddLinuxResourcesNetworkPriorities adds or sets g.Config.Linux.Resources.Network.Priorities. +func (g *Generator) AddLinuxResourcesNetworkPriorities(name string, prio uint32) { + g.initConfigLinuxResourcesNetwork() + for i, netPriority := range g.Config.Linux.Resources.Network.Priorities { + if netPriority.Name == name { + g.Config.Linux.Resources.Network.Priorities[i].Priority = prio + return + } + } + interfacePrio := new(rspec.LinuxInterfacePriority) + interfacePrio.Name = name + interfacePrio.Priority = prio + g.Config.Linux.Resources.Network.Priorities = append(g.Config.Linux.Resources.Network.Priorities, *interfacePrio) +} + +// DropLinuxResourcesNetworkPriorities drops one item from g.Config.Linux.Resources.Network.Priorities. +func (g *Generator) DropLinuxResourcesNetworkPriorities(name string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.Network == nil { + return + } + + for i, netPriority := range g.Config.Linux.Resources.Network.Priorities { + if netPriority.Name == name { + g.Config.Linux.Resources.Network.Priorities = append(g.Config.Linux.Resources.Network.Priorities[:i], g.Config.Linux.Resources.Network.Priorities[i+1:]...) + return + } + } +} + +// SetLinuxResourcesPidsLimit sets g.Config.Linux.Resources.Pids.Limit. +func (g *Generator) SetLinuxResourcesPidsLimit(limit int64) { + g.initConfigLinuxResourcesPids() + g.Config.Linux.Resources.Pids.Limit = limit +} + +// ClearLinuxSysctl clears g.Config.Linux.Sysctl. +func (g *Generator) ClearLinuxSysctl() { + if g.Config == nil || g.Config.Linux == nil { + return + } + g.Config.Linux.Sysctl = make(map[string]string) +} + +// AddLinuxSysctl adds a new sysctl config into g.Config.Linux.Sysctl. +func (g *Generator) AddLinuxSysctl(key, value string) { + g.initConfigLinuxSysctl() + g.Config.Linux.Sysctl[key] = value +} + +// RemoveLinuxSysctl removes a sysctl config from g.Config.Linux.Sysctl. +func (g *Generator) RemoveLinuxSysctl(key string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Sysctl == nil { + return + } + delete(g.Config.Linux.Sysctl, key) +} + +// ClearLinuxUIDMappings clear g.Config.Linux.UIDMappings. +func (g *Generator) ClearLinuxUIDMappings() { + if g.Config == nil || g.Config.Linux == nil { + return + } + g.Config.Linux.UIDMappings = []rspec.LinuxIDMapping{} +} + +// AddLinuxUIDMapping adds uidMap into g.Config.Linux.UIDMappings. +func (g *Generator) AddLinuxUIDMapping(hid, cid, size uint32) { + idMapping := rspec.LinuxIDMapping{ + HostID: hid, + ContainerID: cid, + Size: size, + } + + g.initConfigLinux() + g.Config.Linux.UIDMappings = append(g.Config.Linux.UIDMappings, idMapping) +} + +// ClearLinuxGIDMappings clear g.Config.Linux.GIDMappings. +func (g *Generator) ClearLinuxGIDMappings() { + if g.Config == nil || g.Config.Linux == nil { + return + } + g.Config.Linux.GIDMappings = []rspec.LinuxIDMapping{} +} + +// AddLinuxGIDMapping adds gidMap into g.Config.Linux.GIDMappings. +func (g *Generator) AddLinuxGIDMapping(hid, cid, size uint32) { + idMapping := rspec.LinuxIDMapping{ + HostID: hid, + ContainerID: cid, + Size: size, + } + + g.initConfigLinux() + g.Config.Linux.GIDMappings = append(g.Config.Linux.GIDMappings, idMapping) +} + +// SetLinuxRootPropagation sets g.Config.Linux.RootfsPropagation. +func (g *Generator) SetLinuxRootPropagation(rp string) error { + switch rp { + case "": + case "private": + case "rprivate": + case "slave": + case "rslave": + case "shared": + case "rshared": + case "unbindable": + case "runbindable": + default: + return fmt.Errorf("rootfs-propagation %q must be empty or one of (r)private|(r)slave|(r)shared|(r)unbindable", rp) + } + g.initConfigLinux() + g.Config.Linux.RootfsPropagation = rp + return nil +} + +// ClearPreStartHooks clear g.Config.Hooks.Prestart. +func (g *Generator) ClearPreStartHooks() { + if g.Config == nil || g.Config.Hooks == nil { + return + } + g.Config.Hooks.Prestart = []rspec.Hook{} +} + +// AddPreStartHook add a prestart hook into g.Config.Hooks.Prestart. +func (g *Generator) AddPreStartHook(preStartHook rspec.Hook) { + g.initConfigHooks() + g.Config.Hooks.Prestart = append(g.Config.Hooks.Prestart, preStartHook) +} + +// ClearPostStopHooks clear g.Config.Hooks.Poststop. +func (g *Generator) ClearPostStopHooks() { + if g.Config == nil || g.Config.Hooks == nil { + return + } + g.Config.Hooks.Poststop = []rspec.Hook{} +} + +// AddPostStopHook adds a poststop hook into g.Config.Hooks.Poststop. +func (g *Generator) AddPostStopHook(postStopHook rspec.Hook) { + g.initConfigHooks() + g.Config.Hooks.Poststop = append(g.Config.Hooks.Poststop, postStopHook) +} + +// ClearPostStartHooks clear g.Config.Hooks.Poststart. +func (g *Generator) ClearPostStartHooks() { + if g.Config == nil || g.Config.Hooks == nil { + return + } + g.Config.Hooks.Poststart = []rspec.Hook{} +} + +// AddPostStartHook adds a poststart hook into g.Config.Hooks.Poststart. +func (g *Generator) AddPostStartHook(postStartHook rspec.Hook) { + g.initConfigHooks() + g.Config.Hooks.Poststart = append(g.Config.Hooks.Poststart, postStartHook) +} + +// AddMount adds a mount into g.Config.Mounts. +func (g *Generator) AddMount(mnt rspec.Mount) { + g.initConfig() + + g.Config.Mounts = append(g.Config.Mounts, mnt) +} + +// RemoveMount removes a mount point on the dest directory +func (g *Generator) RemoveMount(dest string) { + g.initConfig() + + for index, mount := range g.Config.Mounts { + if mount.Destination == dest { + g.Config.Mounts = append(g.Config.Mounts[:index], g.Config.Mounts[index+1:]...) + return + } + } +} + +// Mounts returns the list of mounts +func (g *Generator) Mounts() []rspec.Mount { + g.initConfig() + + return g.Config.Mounts +} + +// ClearMounts clear g.Config.Mounts +func (g *Generator) ClearMounts() { + if g.Config == nil { + return + } + g.Config.Mounts = []rspec.Mount{} +} + +// SetupPrivileged sets up the privilege-related fields inside g.Config. +func (g *Generator) SetupPrivileged(privileged bool) { + if privileged { // Add all capabilities in privileged mode. + var finalCapList []string + for _, cap := range capability.List() { + if g.HostSpecific && cap > capsCheck.LastCap() { + continue + } + finalCapList = append(finalCapList, fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String()))) + } + g.initConfigLinux() + g.initConfigProcessCapabilities() + g.ClearProcessCapabilities() + g.Config.Process.Capabilities.Bounding = append(g.Config.Process.Capabilities.Bounding, finalCapList...) + g.Config.Process.Capabilities.Effective = append(g.Config.Process.Capabilities.Effective, finalCapList...) + g.Config.Process.Capabilities.Inheritable = append(g.Config.Process.Capabilities.Inheritable, finalCapList...) + g.Config.Process.Capabilities.Permitted = append(g.Config.Process.Capabilities.Permitted, finalCapList...) + g.Config.Process.Capabilities.Ambient = append(g.Config.Process.Capabilities.Ambient, finalCapList...) + g.Config.Process.SelinuxLabel = "" + g.Config.Process.ApparmorProfile = "" + g.Config.Linux.Seccomp = nil + } +} + +// ClearProcessCapabilities clear g.Config.Process.Capabilities. +func (g *Generator) ClearProcessCapabilities() { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return + } + g.Config.Process.Capabilities.Bounding = []string{} + g.Config.Process.Capabilities.Effective = []string{} + g.Config.Process.Capabilities.Inheritable = []string{} + g.Config.Process.Capabilities.Permitted = []string{} + g.Config.Process.Capabilities.Ambient = []string{} +} + +// AddProcessCapability adds a process capability into all 5 capability sets. +func (g *Generator) AddProcessCapability(c string) error { + cp := strings.ToUpper(c) + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundAmbient, foundBounding, foundEffective, foundInheritable, foundPermitted bool + for _, cap := range g.Config.Process.Capabilities.Ambient { + if strings.ToUpper(cap) == cp { + foundAmbient = true + break + } + } + if !foundAmbient { + g.Config.Process.Capabilities.Ambient = append(g.Config.Process.Capabilities.Ambient, cp) + } + + for _, cap := range g.Config.Process.Capabilities.Bounding { + if strings.ToUpper(cap) == cp { + foundBounding = true + break + } + } + if !foundBounding { + g.Config.Process.Capabilities.Bounding = append(g.Config.Process.Capabilities.Bounding, cp) + } + + for _, cap := range g.Config.Process.Capabilities.Effective { + if strings.ToUpper(cap) == cp { + foundEffective = true + break + } + } + if !foundEffective { + g.Config.Process.Capabilities.Effective = append(g.Config.Process.Capabilities.Effective, cp) + } + + for _, cap := range g.Config.Process.Capabilities.Inheritable { + if strings.ToUpper(cap) == cp { + foundInheritable = true + break + } + } + if !foundInheritable { + g.Config.Process.Capabilities.Inheritable = append(g.Config.Process.Capabilities.Inheritable, cp) + } + + for _, cap := range g.Config.Process.Capabilities.Permitted { + if strings.ToUpper(cap) == cp { + foundPermitted = true + break + } + } + if !foundPermitted { + g.Config.Process.Capabilities.Permitted = append(g.Config.Process.Capabilities.Permitted, cp) + } + + return nil +} + +// AddProcessCapabilityAmbient adds a process capability into g.Config.Process.Capabilities.Ambient. +func (g *Generator) AddProcessCapabilityAmbient(c string) error { + cp := strings.ToUpper(c) + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundAmbient bool + for _, cap := range g.Config.Process.Capabilities.Ambient { + if strings.ToUpper(cap) == cp { + foundAmbient = true + break + } + } + + if !foundAmbient { + g.Config.Process.Capabilities.Ambient = append(g.Config.Process.Capabilities.Ambient, cp) + } + + return nil +} + +// AddProcessCapabilityBounding adds a process capability into g.Config.Process.Capabilities.Bounding. +func (g *Generator) AddProcessCapabilityBounding(c string) error { + cp := strings.ToUpper(c) + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundBounding bool + for _, cap := range g.Config.Process.Capabilities.Bounding { + if strings.ToUpper(cap) == cp { + foundBounding = true + break + } + } + if !foundBounding { + g.Config.Process.Capabilities.Bounding = append(g.Config.Process.Capabilities.Bounding, cp) + } + + return nil +} + +// AddProcessCapabilityEffective adds a process capability into g.Config.Process.Capabilities.Effective. +func (g *Generator) AddProcessCapabilityEffective(c string) error { + cp := strings.ToUpper(c) + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundEffective bool + for _, cap := range g.Config.Process.Capabilities.Effective { + if strings.ToUpper(cap) == cp { + foundEffective = true + break + } + } + if !foundEffective { + g.Config.Process.Capabilities.Effective = append(g.Config.Process.Capabilities.Effective, cp) + } + + return nil +} + +// AddProcessCapabilityInheritable adds a process capability into g.Config.Process.Capabilities.Inheritable. +func (g *Generator) AddProcessCapabilityInheritable(c string) error { + cp := strings.ToUpper(c) + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundInheritable bool + for _, cap := range g.Config.Process.Capabilities.Inheritable { + if strings.ToUpper(cap) == cp { + foundInheritable = true + break + } + } + if !foundInheritable { + g.Config.Process.Capabilities.Inheritable = append(g.Config.Process.Capabilities.Inheritable, cp) + } + + return nil +} + +// AddProcessCapabilityPermitted adds a process capability into g.Config.Process.Capabilities.Permitted. +func (g *Generator) AddProcessCapabilityPermitted(c string) error { + cp := strings.ToUpper(c) + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundPermitted bool + for _, cap := range g.Config.Process.Capabilities.Permitted { + if strings.ToUpper(cap) == cp { + foundPermitted = true + break + } + } + if !foundPermitted { + g.Config.Process.Capabilities.Permitted = append(g.Config.Process.Capabilities.Permitted, cp) + } + + return nil +} + +// DropProcessCapability drops a process capability from all 5 capability sets. +func (g *Generator) DropProcessCapability(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Ambient { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Ambient = removeFunc(g.Config.Process.Capabilities.Ambient, i) + } + } + for i, cap := range g.Config.Process.Capabilities.Bounding { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Bounding = removeFunc(g.Config.Process.Capabilities.Bounding, i) + } + } + for i, cap := range g.Config.Process.Capabilities.Effective { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Effective = removeFunc(g.Config.Process.Capabilities.Effective, i) + } + } + for i, cap := range g.Config.Process.Capabilities.Inheritable { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Inheritable = removeFunc(g.Config.Process.Capabilities.Inheritable, i) + } + } + for i, cap := range g.Config.Process.Capabilities.Permitted { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Permitted = removeFunc(g.Config.Process.Capabilities.Permitted, i) + } + } + + return capsCheck.CapValid(cp, false) +} + +// DropProcessCapabilityAmbient drops a process capability from g.Config.Process.Capabilities.Ambient. +func (g *Generator) DropProcessCapabilityAmbient(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Ambient { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Ambient = removeFunc(g.Config.Process.Capabilities.Ambient, i) + } + } + + return capsCheck.CapValid(cp, false) +} + +// DropProcessCapabilityBounding drops a process capability from g.Config.Process.Capabilities.Bounding. +func (g *Generator) DropProcessCapabilityBounding(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Bounding { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Bounding = removeFunc(g.Config.Process.Capabilities.Bounding, i) + } + } + + return capsCheck.CapValid(cp, false) +} + +// DropProcessCapabilityEffective drops a process capability from g.Config.Process.Capabilities.Effective. +func (g *Generator) DropProcessCapabilityEffective(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Effective { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Effective = removeFunc(g.Config.Process.Capabilities.Effective, i) + } + } + + return capsCheck.CapValid(cp, false) +} + +// DropProcessCapabilityInheritable drops a process capability from g.Config.Process.Capabilities.Inheritable. +func (g *Generator) DropProcessCapabilityInheritable(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Inheritable { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Inheritable = removeFunc(g.Config.Process.Capabilities.Inheritable, i) + } + } + + return capsCheck.CapValid(cp, false) +} + +// DropProcessCapabilityPermitted drops a process capability from g.Config.Process.Capabilities.Permitted. +func (g *Generator) DropProcessCapabilityPermitted(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Permitted { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Permitted = removeFunc(g.Config.Process.Capabilities.Permitted, i) + } + } + + return capsCheck.CapValid(cp, false) +} + +func mapStrToNamespace(ns string, path string) (rspec.LinuxNamespace, error) { + switch ns { + case "network": + return rspec.LinuxNamespace{Type: rspec.NetworkNamespace, Path: path}, nil + case "pid": + return rspec.LinuxNamespace{Type: rspec.PIDNamespace, Path: path}, nil + case "mount": + return rspec.LinuxNamespace{Type: rspec.MountNamespace, Path: path}, nil + case "ipc": + return rspec.LinuxNamespace{Type: rspec.IPCNamespace, Path: path}, nil + case "uts": + return rspec.LinuxNamespace{Type: rspec.UTSNamespace, Path: path}, nil + case "user": + return rspec.LinuxNamespace{Type: rspec.UserNamespace, Path: path}, nil + case "cgroup": + return rspec.LinuxNamespace{Type: rspec.CgroupNamespace, Path: path}, nil + default: + return rspec.LinuxNamespace{}, fmt.Errorf("unrecognized namespace %q", ns) + } +} + +// ClearLinuxNamespaces clear g.Config.Linux.Namespaces. +func (g *Generator) ClearLinuxNamespaces() { + if g.Config == nil || g.Config.Linux == nil { + return + } + g.Config.Linux.Namespaces = []rspec.LinuxNamespace{} +} + +// AddOrReplaceLinuxNamespace adds or replaces a namespace inside +// g.Config.Linux.Namespaces. +func (g *Generator) AddOrReplaceLinuxNamespace(ns string, path string) error { + namespace, err := mapStrToNamespace(ns, path) + if err != nil { + return err + } + + g.initConfigLinux() + for i, ns := range g.Config.Linux.Namespaces { + if ns.Type == namespace.Type { + g.Config.Linux.Namespaces[i] = namespace + return nil + } + } + g.Config.Linux.Namespaces = append(g.Config.Linux.Namespaces, namespace) + return nil +} + +// RemoveLinuxNamespace removes a namespace from g.Config.Linux.Namespaces. +func (g *Generator) RemoveLinuxNamespace(ns string) error { + namespace, err := mapStrToNamespace(ns, "") + if err != nil { + return err + } + + if g.Config == nil || g.Config.Linux == nil { + return nil + } + for i, ns := range g.Config.Linux.Namespaces { + if ns.Type == namespace.Type { + g.Config.Linux.Namespaces = append(g.Config.Linux.Namespaces[:i], g.Config.Linux.Namespaces[i+1:]...) + return nil + } + } + return nil +} + +// AddDevice - add a device into g.Config.Linux.Devices +func (g *Generator) AddDevice(device rspec.LinuxDevice) { + g.initConfigLinux() + + for i, dev := range g.Config.Linux.Devices { + if dev.Path == device.Path { + g.Config.Linux.Devices[i] = device + return + } + } + + g.Config.Linux.Devices = append(g.Config.Linux.Devices, device) +} + +// RemoveDevice remove a device from g.Config.Linux.Devices +func (g *Generator) RemoveDevice(path string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Devices == nil { + return + } + + for i, device := range g.Config.Linux.Devices { + if device.Path == path { + g.Config.Linux.Devices = append(g.Config.Linux.Devices[:i], g.Config.Linux.Devices[i+1:]...) + return + } + } +} + +// ClearLinuxDevices clears g.Config.Linux.Devices +func (g *Generator) ClearLinuxDevices() { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Devices == nil { + return + } + + g.Config.Linux.Devices = []rspec.LinuxDevice{} +} + +// AddLinuxResourcesDevice - add a device into g.Config.Linux.Resources.Devices +func (g *Generator) AddLinuxResourcesDevice(allow bool, devType string, major, minor *int64, access string) { + g.initConfigLinuxResources() + + device := rspec.LinuxDeviceCgroup{ + Allow: allow, + Type: devType, + Access: access, + Major: major, + Minor: minor, + } + g.Config.Linux.Resources.Devices = append(g.Config.Linux.Resources.Devices, device) +} + +// RemoveLinuxResourcesDevice - remove a device from g.Config.Linux.Resources.Devices +func (g *Generator) RemoveLinuxResourcesDevice(allow bool, devType string, major, minor *int64, access string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil { + return + } + for i, device := range g.Config.Linux.Resources.Devices { + if device.Allow == allow && + (devType == device.Type || (devType != "" && device.Type != "" && devType == device.Type)) && + (access == device.Access || (access != "" && device.Access != "" && access == device.Access)) && + (major == device.Major || (major != nil && device.Major != nil && *major == *device.Major)) && + (minor == device.Minor || (minor != nil && device.Minor != nil && *minor == *device.Minor)) { + + g.Config.Linux.Resources.Devices = append(g.Config.Linux.Resources.Devices[:i], g.Config.Linux.Resources.Devices[i+1:]...) + return + } + } +} + +// SetSyscallAction adds rules for syscalls with the specified action +func (g *Generator) SetSyscallAction(arguments seccomp.SyscallOpts) error { + g.initConfigLinuxSeccomp() + return seccomp.ParseSyscallFlag(arguments, g.Config.Linux.Seccomp) +} + +// SetDefaultSeccompAction sets the default action for all syscalls not defined +// and then removes any syscall rules with this action already specified. +func (g *Generator) SetDefaultSeccompAction(action string) error { + g.initConfigLinuxSeccomp() + return seccomp.ParseDefaultAction(action, g.Config.Linux.Seccomp) +} + +// SetDefaultSeccompActionForce only sets the default action for all syscalls not defined +func (g *Generator) SetDefaultSeccompActionForce(action string) error { + g.initConfigLinuxSeccomp() + return seccomp.ParseDefaultActionForce(action, g.Config.Linux.Seccomp) +} + +// SetDomainName sets g.Config.Domainname +func (g *Generator) SetDomainName(domain string) { + g.initConfig() + g.Config.Domainname = domain +} + +// SetSeccompArchitecture sets the supported seccomp architectures +func (g *Generator) SetSeccompArchitecture(architecture string) error { + g.initConfigLinuxSeccomp() + return seccomp.ParseArchitectureFlag(architecture, g.Config.Linux.Seccomp) +} + +// RemoveSeccompRule removes rules for any specified syscalls +func (g *Generator) RemoveSeccompRule(arguments string) error { + g.initConfigLinuxSeccomp() + return seccomp.RemoveAction(arguments, g.Config.Linux.Seccomp) +} + +// RemoveAllSeccompRules removes all syscall rules +func (g *Generator) RemoveAllSeccompRules() error { + g.initConfigLinuxSeccomp() + return seccomp.RemoveAllSeccompRules(g.Config.Linux.Seccomp) +} + +// AddLinuxMaskedPaths adds masked paths into g.Config.Linux.MaskedPaths. +func (g *Generator) AddLinuxMaskedPaths(path string) { + g.initConfigLinux() + g.Config.Linux.MaskedPaths = append(g.Config.Linux.MaskedPaths, path) +} + +// AddLinuxReadonlyPaths adds readonly paths into g.Config.Linux.MaskedPaths. +func (g *Generator) AddLinuxReadonlyPaths(path string) { + g.initConfigLinux() + g.Config.Linux.ReadonlyPaths = append(g.Config.Linux.ReadonlyPaths, path) +} + +func addOrReplaceBlockIOThrottleDevice(tmpList []rspec.LinuxThrottleDevice, major int64, minor int64, rate uint64) []rspec.LinuxThrottleDevice { + throttleDevices := tmpList + for i, throttleDevice := range throttleDevices { + if throttleDevice.Major == major && throttleDevice.Minor == minor { + throttleDevices[i].Rate = rate + return throttleDevices + } + } + throttleDevice := new(rspec.LinuxThrottleDevice) + throttleDevice.Major = major + throttleDevice.Minor = minor + throttleDevice.Rate = rate + throttleDevices = append(throttleDevices, *throttleDevice) + + return throttleDevices +} + +func dropBlockIOThrottleDevice(tmpList []rspec.LinuxThrottleDevice, major int64, minor int64) []rspec.LinuxThrottleDevice { + throttleDevices := tmpList + for i, throttleDevice := range throttleDevices { + if throttleDevice.Major == major && throttleDevice.Minor == minor { + throttleDevices = append(throttleDevices[:i], throttleDevices[i+1:]...) + return throttleDevices + } + } + + return throttleDevices +} + +// AddSolarisAnet adds network into g.Config.Solaris.Anet +func (g *Generator) AddSolarisAnet(anet rspec.SolarisAnet) { + g.initConfigSolaris() + g.Config.Solaris.Anet = append(g.Config.Solaris.Anet, anet) +} + +// SetSolarisCappedCPUNcpus sets g.Config.Solaris.CappedCPU.Ncpus +func (g *Generator) SetSolarisCappedCPUNcpus(ncpus string) { + g.initConfigSolarisCappedCPU() + g.Config.Solaris.CappedCPU.Ncpus = ncpus +} + +// SetSolarisCappedMemoryPhysical sets g.Config.Solaris.CappedMemory.Physical +func (g *Generator) SetSolarisCappedMemoryPhysical(physical string) { + g.initConfigSolarisCappedMemory() + g.Config.Solaris.CappedMemory.Physical = physical +} + +// SetSolarisCappedMemorySwap sets g.Config.Solaris.CappedMemory.Swap +func (g *Generator) SetSolarisCappedMemorySwap(swap string) { + g.initConfigSolarisCappedMemory() + g.Config.Solaris.CappedMemory.Swap = swap +} + +// SetSolarisLimitPriv sets g.Config.Solaris.LimitPriv +func (g *Generator) SetSolarisLimitPriv(limitPriv string) { + g.initConfigSolaris() + g.Config.Solaris.LimitPriv = limitPriv +} + +// SetSolarisMaxShmMemory sets g.Config.Solaris.MaxShmMemory +func (g *Generator) SetSolarisMaxShmMemory(memory string) { + g.initConfigSolaris() + g.Config.Solaris.MaxShmMemory = memory +} + +// SetSolarisMilestone sets g.Config.Solaris.Milestone +func (g *Generator) SetSolarisMilestone(milestone string) { + g.initConfigSolaris() + g.Config.Solaris.Milestone = milestone +} + +// SetVMHypervisorPath sets g.Config.VM.Hypervisor.Path +func (g *Generator) SetVMHypervisorPath(path string) error { + if !strings.HasPrefix(path, "/") { + return fmt.Errorf("hypervisorPath %v is not an absolute path", path) + } + g.initConfigVM() + g.Config.VM.Hypervisor.Path = path + return nil +} + +// SetVMHypervisorParameters sets g.Config.VM.Hypervisor.Parameters +func (g *Generator) SetVMHypervisorParameters(parameters []string) { + g.initConfigVM() + g.Config.VM.Hypervisor.Parameters = parameters +} + +// SetVMKernelPath sets g.Config.VM.Kernel.Path +func (g *Generator) SetVMKernelPath(path string) error { + if !strings.HasPrefix(path, "/") { + return fmt.Errorf("kernelPath %v is not an absolute path", path) + } + g.initConfigVM() + g.Config.VM.Kernel.Path = path + return nil +} + +// SetVMKernelParameters sets g.Config.VM.Kernel.Parameters +func (g *Generator) SetVMKernelParameters(parameters []string) { + g.initConfigVM() + g.Config.VM.Kernel.Parameters = parameters +} + +// SetVMKernelInitRD sets g.Config.VM.Kernel.InitRD +func (g *Generator) SetVMKernelInitRD(initrd string) error { + if !strings.HasPrefix(initrd, "/") { + return fmt.Errorf("kernelInitrd %v is not an absolute path", initrd) + } + g.initConfigVM() + g.Config.VM.Kernel.InitRD = initrd + return nil +} + +// SetVMImagePath sets g.Config.VM.Image.Path +func (g *Generator) SetVMImagePath(path string) error { + if !strings.HasPrefix(path, "/") { + return fmt.Errorf("imagePath %v is not an absolute path", path) + } + g.initConfigVM() + g.Config.VM.Image.Path = path + return nil +} + +// SetVMImageFormat sets g.Config.VM.Image.Format +func (g *Generator) SetVMImageFormat(format string) error { + switch format { + case "raw": + case "qcow2": + case "vdi": + case "vmdk": + case "vhd": + default: + return fmt.Errorf("Commonly supported formats are: raw, qcow2, vdi, vmdk, vhd") + } + g.initConfigVM() + g.Config.VM.Image.Format = format + return nil +} + +// SetWindowsHypervUntilityVMPath sets g.Config.Windows.HyperV.UtilityVMPath. +func (g *Generator) SetWindowsHypervUntilityVMPath(path string) { + g.initConfigWindowsHyperV() + g.Config.Windows.HyperV.UtilityVMPath = path +} + +// SetWindowsIgnoreFlushesDuringBoot sets g.Config.Windows.IgnoreFlushesDuringBoot. +func (g *Generator) SetWindowsIgnoreFlushesDuringBoot(ignore bool) { + g.initConfigWindows() + g.Config.Windows.IgnoreFlushesDuringBoot = ignore +} + +// AddWindowsLayerFolders adds layer folders into g.Config.Windows.LayerFolders. +func (g *Generator) AddWindowsLayerFolders(folder string) { + g.initConfigWindows() + g.Config.Windows.LayerFolders = append(g.Config.Windows.LayerFolders, folder) +} + +// AddWindowsDevices adds or sets g.Config.Windwos.Devices +func (g *Generator) AddWindowsDevices(id, idType string) error { + if idType != "class" { + return fmt.Errorf("Invalid idType value: %s. Windows only supports a value of class", idType) + } + device := rspec.WindowsDevice{ + ID: id, + IDType: idType, + } + + g.initConfigWindows() + for i, device := range g.Config.Windows.Devices { + if device.ID == id { + g.Config.Windows.Devices[i].IDType = idType + return nil + } + } + g.Config.Windows.Devices = append(g.Config.Windows.Devices, device) + return nil +} + +// SetWindowsNetwork sets g.Config.Windows.Network. +func (g *Generator) SetWindowsNetwork(network rspec.WindowsNetwork) { + g.initConfigWindows() + g.Config.Windows.Network = &network +} + +// SetWindowsNetworkAllowUnqualifiedDNSQuery sets g.Config.Windows.Network.AllowUnqualifiedDNSQuery +func (g *Generator) SetWindowsNetworkAllowUnqualifiedDNSQuery(setting bool) { + g.initConfigWindowsNetwork() + g.Config.Windows.Network.AllowUnqualifiedDNSQuery = setting +} + +// SetWindowsNetworkNamespace sets g.Config.Windows.Network.NetworkNamespace +func (g *Generator) SetWindowsNetworkNamespace(path string) { + g.initConfigWindowsNetwork() + g.Config.Windows.Network.NetworkNamespace = path +} + +// SetWindowsResourcesCPU sets g.Config.Windows.Resources.CPU. +func (g *Generator) SetWindowsResourcesCPU(cpu rspec.WindowsCPUResources) { + g.initConfigWindowsResources() + g.Config.Windows.Resources.CPU = &cpu +} + +// SetWindowsResourcesMemoryLimit sets g.Config.Windows.Resources.Memory.Limit. +func (g *Generator) SetWindowsResourcesMemoryLimit(limit uint64) { + g.initConfigWindowsResourcesMemory() + g.Config.Windows.Resources.Memory.Limit = &limit +} + +// SetWindowsResourcesStorage sets g.Config.Windows.Resources.Storage. +func (g *Generator) SetWindowsResourcesStorage(storage rspec.WindowsStorageResources) { + g.initConfigWindowsResources() + g.Config.Windows.Resources.Storage = &storage +} + +// SetWindowsServicing sets g.Config.Windows.Servicing. +func (g *Generator) SetWindowsServicing(servicing bool) { + g.initConfigWindows() + g.Config.Windows.Servicing = servicing +} diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go new file mode 100644 index 00000000..f28d8f58 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go @@ -0,0 +1,7 @@ +package seccomp + +const ( + seccompOverwrite = "overwrite" + seccompAppend = "append" + nothing = "nothing" +) diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go new file mode 100644 index 00000000..25daf075 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go @@ -0,0 +1,135 @@ +package seccomp + +import ( + "fmt" + "strconv" + "strings" + + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +// SyscallOpts contain options for parsing syscall rules +type SyscallOpts struct { + Action string + Syscall string + Index string + Value string + ValueTwo string + Operator string +} + +// ParseSyscallFlag takes a SyscallOpts struct and the seccomp configuration +// and sets the new syscall rule accordingly +func ParseSyscallFlag(args SyscallOpts, config *rspec.LinuxSeccomp) error { + var arguments []string + if args.Index != "" && args.Value != "" && args.ValueTwo != "" && args.Operator != "" { + arguments = []string{args.Action, args.Syscall, args.Index, args.Value, + args.ValueTwo, args.Operator} + } else { + arguments = []string{args.Action, args.Syscall} + } + + action, _ := parseAction(arguments[0]) + if action == config.DefaultAction && args.argsAreEmpty() { + // default already set, no need to make changes + return nil + } + + var newSyscall rspec.LinuxSyscall + numOfArgs := len(arguments) + if numOfArgs == 6 || numOfArgs == 2 { + argStruct, err := parseArguments(arguments[1:]) + if err != nil { + return err + } + newSyscall = newSyscallStruct(arguments[1], action, argStruct) + } else { + return fmt.Errorf("incorrect number of arguments to ParseSyscall: %d", numOfArgs) + } + + descison, err := decideCourseOfAction(&newSyscall, config.Syscalls) + if err != nil { + return err + } + delimDescison := strings.Split(descison, ":") + + if delimDescison[0] == seccompAppend { + config.Syscalls = append(config.Syscalls, newSyscall) + } + + if delimDescison[0] == seccompOverwrite { + indexForOverwrite, err := strconv.ParseInt(delimDescison[1], 10, 32) + if err != nil { + return err + } + config.Syscalls[indexForOverwrite] = newSyscall + } + + return nil +} + +var actions = map[string]rspec.LinuxSeccompAction{ + "allow": rspec.ActAllow, + "errno": rspec.ActErrno, + "kill": rspec.ActKill, + "trace": rspec.ActTrace, + "trap": rspec.ActTrap, +} + +// Take passed action, return the SCMP_ACT_ version of it +func parseAction(action string) (rspec.LinuxSeccompAction, error) { + a, ok := actions[action] + if !ok { + return "", fmt.Errorf("unrecognized action: %s", action) + } + return a, nil +} + +// ParseDefaultAction sets the default action of the seccomp configuration +// and then removes any rules that were already specified with this action +func ParseDefaultAction(action string, config *rspec.LinuxSeccomp) error { + if action == "" { + return nil + } + + defaultAction, err := parseAction(action) + if err != nil { + return err + } + config.DefaultAction = defaultAction + err = RemoveAllMatchingRules(config, defaultAction) + if err != nil { + return err + } + return nil +} + +// ParseDefaultActionForce simply sets the default action of the seccomp configuration +func ParseDefaultActionForce(action string, config *rspec.LinuxSeccomp) error { + if action == "" { + return nil + } + + defaultAction, err := parseAction(action) + if err != nil { + return err + } + config.DefaultAction = defaultAction + return nil +} + +func newSyscallStruct(name string, action rspec.LinuxSeccompAction, args []rspec.LinuxSeccompArg) rspec.LinuxSyscall { + syscallStruct := rspec.LinuxSyscall{ + Names: []string{name}, + Action: action, + Args: args, + } + return syscallStruct +} + +func (s SyscallOpts) argsAreEmpty() bool { + return (s.Index == "" && + s.Value == "" && + s.ValueTwo == "" && + s.Operator == "") +} diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go new file mode 100644 index 00000000..9b2bdfd2 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go @@ -0,0 +1,55 @@ +package seccomp + +import ( + "fmt" + + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +// ParseArchitectureFlag takes the raw string passed with the --arch flag, parses it +// and updates the Seccomp config accordingly +func ParseArchitectureFlag(architectureArg string, config *rspec.LinuxSeccomp) error { + correctedArch, err := parseArch(architectureArg) + if err != nil { + return err + } + + shouldAppend := true + for _, alreadySpecified := range config.Architectures { + if correctedArch == alreadySpecified { + shouldAppend = false + } + } + if shouldAppend { + config.Architectures = append(config.Architectures, correctedArch) + } + return nil +} + +func parseArch(arch string) (rspec.Arch, error) { + arches := map[string]rspec.Arch{ + "x86": rspec.ArchX86, + "amd64": rspec.ArchX86_64, + "x32": rspec.ArchX32, + "arm": rspec.ArchARM, + "arm64": rspec.ArchAARCH64, + "mips": rspec.ArchMIPS, + "mips64": rspec.ArchMIPS64, + "mips64n32": rspec.ArchMIPS64N32, + "mipsel": rspec.ArchMIPSEL, + "mipsel64": rspec.ArchMIPSEL64, + "mipsel64n32": rspec.ArchMIPSEL64N32, + "parisc": rspec.ArchPARISC, + "parisc64": rspec.ArchPARISC64, + "ppc": rspec.ArchPPC, + "ppc64": rspec.ArchPPC64, + "ppc64le": rspec.ArchPPC64LE, + "s390": rspec.ArchS390, + "s390x": rspec.ArchS390X, + } + a, ok := arches[arch] + if !ok { + return "", fmt.Errorf("unrecognized architecture: %s", arch) + } + return a, nil +} diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go new file mode 100644 index 00000000..2b4c394e --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go @@ -0,0 +1,73 @@ +package seccomp + +import ( + "fmt" + "strconv" + + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +// parseArguments takes a list of arguments (delimArgs). It parses and fills out +// the argument information and returns a slice of arg structs +func parseArguments(delimArgs []string) ([]rspec.LinuxSeccompArg, error) { + nilArgSlice := []rspec.LinuxSeccompArg{} + numberOfArgs := len(delimArgs) + + // No parameters passed with syscall + if numberOfArgs == 1 { + return nilArgSlice, nil + } + + // Correct number of parameters passed with syscall + if numberOfArgs == 5 { + syscallIndex, err := strconv.ParseUint(delimArgs[1], 10, 0) + if err != nil { + return nilArgSlice, err + } + + syscallValue, err := strconv.ParseUint(delimArgs[2], 10, 64) + if err != nil { + return nilArgSlice, err + } + + syscallValueTwo, err := strconv.ParseUint(delimArgs[3], 10, 64) + if err != nil { + return nilArgSlice, err + } + + syscallOp, err := parseOperator(delimArgs[4]) + if err != nil { + return nilArgSlice, err + } + + argStruct := rspec.LinuxSeccompArg{ + Index: uint(syscallIndex), + Value: syscallValue, + ValueTwo: syscallValueTwo, + Op: syscallOp, + } + + argSlice := []rspec.LinuxSeccompArg{} + argSlice = append(argSlice, argStruct) + return argSlice, nil + } + + return nilArgSlice, fmt.Errorf("incorrect number of arguments passed with syscall: %d", numberOfArgs) +} + +func parseOperator(operator string) (rspec.LinuxSeccompOperator, error) { + operators := map[string]rspec.LinuxSeccompOperator{ + "NE": rspec.OpNotEqual, + "LT": rspec.OpLessThan, + "LE": rspec.OpLessEqual, + "EQ": rspec.OpEqualTo, + "GE": rspec.OpGreaterEqual, + "GT": rspec.OpGreaterThan, + "ME": rspec.OpMaskedEqual, + } + o, ok := operators[operator] + if !ok { + return "", fmt.Errorf("unrecognized operator: %s", operator) + } + return o, nil +} diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go new file mode 100644 index 00000000..59537d49 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go @@ -0,0 +1,52 @@ +package seccomp + +import ( + "fmt" + "reflect" + "strings" + + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +// RemoveAction takes the argument string that was passed with the --remove flag, +// parses it, and updates the Seccomp config accordingly +func RemoveAction(arguments string, config *rspec.LinuxSeccomp) error { + if config == nil { + return fmt.Errorf("Cannot remove action from nil Seccomp pointer") + } + + syscallsToRemove := strings.Split(arguments, ",") + + for counter, syscallStruct := range config.Syscalls { + if reflect.DeepEqual(syscallsToRemove, syscallStruct.Names) { + config.Syscalls = append(config.Syscalls[:counter], config.Syscalls[counter+1:]...) + } + } + + return nil +} + +// RemoveAllSeccompRules removes all seccomp syscall rules +func RemoveAllSeccompRules(config *rspec.LinuxSeccomp) error { + if config == nil { + return fmt.Errorf("Cannot remove action from nil Seccomp pointer") + } + newSyscallSlice := []rspec.LinuxSyscall{} + config.Syscalls = newSyscallSlice + return nil +} + +// RemoveAllMatchingRules will remove any syscall rules that match the specified action +func RemoveAllMatchingRules(config *rspec.LinuxSeccomp, seccompAction rspec.LinuxSeccompAction) error { + if config == nil { + return fmt.Errorf("Cannot remove action from nil Seccomp pointer") + } + + for _, syscall := range config.Syscalls { + if reflect.DeepEqual(syscall.Action, seccompAction) { + RemoveAction(strings.Join(syscall.Names, ","), config) + } + } + + return nil +} diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go new file mode 100644 index 00000000..345a32a6 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go @@ -0,0 +1,606 @@ +package seccomp + +import ( + "runtime" + + "github.com/opencontainers/runtime-spec/specs-go" + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +func arches() []rspec.Arch { + native := runtime.GOARCH + + switch native { + case "amd64": + return []rspec.Arch{rspec.ArchX86_64, rspec.ArchX86, rspec.ArchX32} + case "arm64": + return []rspec.Arch{rspec.ArchARM, rspec.ArchAARCH64} + case "mips64": + return []rspec.Arch{rspec.ArchMIPS, rspec.ArchMIPS64, rspec.ArchMIPS64N32} + case "mips64n32": + return []rspec.Arch{rspec.ArchMIPS, rspec.ArchMIPS64, rspec.ArchMIPS64N32} + case "mipsel64": + return []rspec.Arch{rspec.ArchMIPSEL, rspec.ArchMIPSEL64, rspec.ArchMIPSEL64N32} + case "mipsel64n32": + return []rspec.Arch{rspec.ArchMIPSEL, rspec.ArchMIPSEL64, rspec.ArchMIPSEL64N32} + case "s390x": + return []rspec.Arch{rspec.ArchS390, rspec.ArchS390X} + default: + return []rspec.Arch{} + } +} + +// DefaultProfile defines the whitelist for the default seccomp profile. +func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp { + + syscalls := []rspec.LinuxSyscall{ + { + Names: []string{ + "accept", + "accept4", + "access", + "alarm", + "bind", + "brk", + "capget", + "capset", + "chdir", + "chmod", + "chown", + "chown32", + "clock_getres", + "clock_gettime", + "clock_nanosleep", + "close", + "connect", + "copy_file_range", + "creat", + "dup", + "dup2", + "dup3", + "epoll_create", + "epoll_create1", + "epoll_ctl", + "epoll_ctl_old", + "epoll_pwait", + "epoll_wait", + "epoll_wait_old", + "eventfd", + "eventfd2", + "execve", + "execveat", + "exit", + "exit_group", + "faccessat", + "fadvise64", + "fadvise64_64", + "fallocate", + "fanotify_mark", + "fchdir", + "fchmod", + "fchmodat", + "fchown", + "fchown32", + "fchownat", + "fcntl", + "fcntl64", + "fdatasync", + "fgetxattr", + "flistxattr", + "flock", + "fork", + "fremovexattr", + "fsetxattr", + "fstat", + "fstat64", + "fstatat64", + "fstatfs", + "fstatfs64", + "fsync", + "ftruncate", + "ftruncate64", + "futex", + "futimesat", + "getcpu", + "getcwd", + "getdents", + "getdents64", + "getegid", + "getegid32", + "geteuid", + "geteuid32", + "getgid", + "getgid32", + "getgroups", + "getgroups32", + "getitimer", + "getpeername", + "getpgid", + "getpgrp", + "getpid", + "getppid", + "getpriority", + "getrandom", + "getresgid", + "getresgid32", + "getresuid", + "getresuid32", + "getrlimit", + "get_robust_list", + "getrusage", + "getsid", + "getsockname", + "getsockopt", + "get_thread_area", + "gettid", + "gettimeofday", + "getuid", + "getuid32", + "getxattr", + "inotify_add_watch", + "inotify_init", + "inotify_init1", + "inotify_rm_watch", + "io_cancel", + "ioctl", + "io_destroy", + "io_getevents", + "ioprio_get", + "ioprio_set", + "io_setup", + "io_submit", + "ipc", + "kill", + "landlock_add_rule", + "landlock_create_ruleset", + "landlock_restrict_self", + "lchown", + "lchown32", + "lgetxattr", + "link", + "linkat", + "listen", + "listxattr", + "llistxattr", + "_llseek", + "lremovexattr", + "lseek", + "lsetxattr", + "lstat", + "lstat64", + "madvise", + "memfd_create", + "mincore", + "mkdir", + "mkdirat", + "mknod", + "mknodat", + "mlock", + "mlock2", + "mlockall", + "mmap", + "mmap2", + "mprotect", + "mq_getsetattr", + "mq_notify", + "mq_open", + "mq_timedreceive", + "mq_timedsend", + "mq_unlink", + "mremap", + "msgctl", + "msgget", + "msgrcv", + "msgsnd", + "msync", + "munlock", + "munlockall", + "munmap", + "nanosleep", + "newfstatat", + "_newselect", + "open", + "openat", + "pause", + "pipe", + "pipe2", + "poll", + "ppoll", + "prctl", + "pread64", + "preadv", + "prlimit64", + "pselect6", + "pwrite64", + "pwritev", + "read", + "readahead", + "readlink", + "readlinkat", + "readv", + "recv", + "recvfrom", + "recvmmsg", + "recvmsg", + "remap_file_pages", + "removexattr", + "rename", + "renameat", + "renameat2", + "restart_syscall", + "rmdir", + "rt_sigaction", + "rt_sigpending", + "rt_sigprocmask", + "rt_sigqueueinfo", + "rt_sigreturn", + "rt_sigsuspend", + "rt_sigtimedwait", + "rt_tgsigqueueinfo", + "sched_getaffinity", + "sched_getattr", + "sched_getparam", + "sched_get_priority_max", + "sched_get_priority_min", + "sched_getscheduler", + "sched_rr_get_interval", + "sched_setaffinity", + "sched_setattr", + "sched_setparam", + "sched_setscheduler", + "sched_yield", + "seccomp", + "select", + "semctl", + "semget", + "semop", + "semtimedop", + "send", + "sendfile", + "sendfile64", + "sendmmsg", + "sendmsg", + "sendto", + "setfsgid", + "setfsgid32", + "setfsuid", + "setfsuid32", + "setgid", + "setgid32", + "setgroups", + "setgroups32", + "setitimer", + "setpgid", + "setpriority", + "setregid", + "setregid32", + "setresgid", + "setresgid32", + "setresuid", + "setresuid32", + "setreuid", + "setreuid32", + "setrlimit", + "set_robust_list", + "setsid", + "setsockopt", + "set_thread_area", + "set_tid_address", + "setuid", + "setuid32", + "setxattr", + "shmat", + "shmctl", + "shmdt", + "shmget", + "shutdown", + "sigaltstack", + "signalfd", + "signalfd4", + "sigreturn", + "socket", + "socketcall", + "socketpair", + "splice", + "stat", + "stat64", + "statfs", + "statfs64", + "statx", + "symlink", + "symlinkat", + "sync", + "sync_file_range", + "syncfs", + "sysinfo", + "syslog", + "tee", + "tgkill", + "time", + "timer_create", + "timer_delete", + "timerfd_create", + "timerfd_gettime", + "timerfd_settime", + "timer_getoverrun", + "timer_gettime", + "timer_settime", + "times", + "tkill", + "truncate", + "truncate64", + "ugetrlimit", + "umask", + "uname", + "unlink", + "unlinkat", + "utime", + "utimensat", + "utimes", + "vfork", + "vmsplice", + "wait4", + "waitid", + "waitpid", + "write", + "writev", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + { + Names: []string{"personality"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{ + { + Index: 0, + Value: 0x0, + Op: rspec.OpEqualTo, + }, + }, + }, + { + Names: []string{"personality"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{ + { + Index: 0, + Value: 0x0008, + Op: rspec.OpEqualTo, + }, + }, + }, + { + Names: []string{"personality"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{ + { + Index: 0, + Value: 0xffffffff, + Op: rspec.OpEqualTo, + }, + }, + }, + } + var sysCloneFlagsIndex uint + + capSysAdmin := false + caps := make(map[string]bool) + + for _, cap := range rs.Process.Capabilities.Bounding { + caps[cap] = true + } + for _, cap := range rs.Process.Capabilities.Effective { + caps[cap] = true + } + for _, cap := range rs.Process.Capabilities.Inheritable { + caps[cap] = true + } + for _, cap := range rs.Process.Capabilities.Permitted { + caps[cap] = true + } + for _, cap := range rs.Process.Capabilities.Ambient { + caps[cap] = true + } + + for cap := range caps { + switch cap { + case "CAP_DAC_READ_SEARCH": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"open_by_handle_at"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_ADMIN": + capSysAdmin = true + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "bpf", + "clone", + "fanotify_init", + "lookup_dcookie", + "mount", + "name_to_handle_at", + "perf_event_open", + "setdomainname", + "sethostname", + "setns", + "umount", + "umount2", + "unshare", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_BOOT": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"reboot"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_CHROOT": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"chroot"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_MODULE": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "delete_module", + "init_module", + "finit_module", + "query_module", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_PACCT": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"acct"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_PTRACE": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "kcmp", + "process_vm_readv", + "process_vm_writev", + "ptrace", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_RAWIO": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "iopl", + "ioperm", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_TIME": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "settimeofday", + "stime", + "adjtimex", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_TTY_CONFIG": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"vhangup"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + } + } + + if !capSysAdmin { + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"clone"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{ + { + Index: sysCloneFlagsIndex, + Value: CloneNewNS | CloneNewUTS | CloneNewIPC | CloneNewUser | CloneNewPID | CloneNewNet | CloneNewCgroup, + ValueTwo: 0, + Op: rspec.OpMaskedEqual, + }, + }, + }, + }...) + + } + + arch := runtime.GOARCH + switch arch { + case "arm", "arm64": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "breakpoint", + "cacheflush", + "set_tls", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "amd64", "x32": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"arch_prctl"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + fallthrough + case "x86": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"modify_ldt"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "s390", "s390x": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "s390_pci_mmio_read", + "s390_pci_mmio_write", + "s390_runtime_instr", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + /* Flags parameter of the clone syscall is the 2nd on s390 */ + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"clone"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{ + { + Index: 1, + Value: 2080505856, + ValueTwo: 0, + Op: rspec.OpMaskedEqual, + }, + }, + }, + }...) + } + + return &rspec.LinuxSeccomp{ + DefaultAction: rspec.ActErrno, + Architectures: arches(), + Syscalls: syscalls, + } +} diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go new file mode 100644 index 00000000..5ca9a6da --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go @@ -0,0 +1,17 @@ +//go:build linux +// +build linux + +package seccomp + +import "golang.org/x/sys/unix" + +// System values passed through on linux +const ( + CloneNewIPC = unix.CLONE_NEWIPC + CloneNewNet = unix.CLONE_NEWNET + CloneNewNS = unix.CLONE_NEWNS + CloneNewPID = unix.CLONE_NEWPID + CloneNewUser = unix.CLONE_NEWUSER + CloneNewUTS = unix.CLONE_NEWUTS + CloneNewCgroup = unix.CLONE_NEWCGROUP +) diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_unsupported.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_unsupported.go new file mode 100644 index 00000000..b8c1bc26 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_unsupported.go @@ -0,0 +1,16 @@ +//go:build !linux +// +build !linux + +package seccomp + +// These are copied from linux/amd64 syscall values, as a reference for other +// platforms to have access to +const ( + CloneNewIPC = 0x8000000 + CloneNewNet = 0x40000000 + CloneNewNS = 0x20000 + CloneNewPID = 0x20000000 + CloneNewUser = 0x10000000 + CloneNewUTS = 0x4000000 + CloneNewCgroup = 0x02000000 +) diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go new file mode 100644 index 00000000..5e84653a --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go @@ -0,0 +1,124 @@ +package seccomp + +import ( + "fmt" + "reflect" + "strconv" + "strings" + + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +// Determine if a new syscall rule should be appended, overwrite an existing rule +// or if no action should be taken at all +func decideCourseOfAction(newSyscall *rspec.LinuxSyscall, syscalls []rspec.LinuxSyscall) (string, error) { + ruleForSyscallAlreadyExists := false + + var sliceOfDeterminedActions []string + for i, syscall := range syscalls { + if sameName(&syscall, newSyscall) { + ruleForSyscallAlreadyExists = true + + if identical(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, nothing) + } + + if sameAction(newSyscall, &syscall) { + if bothHaveArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend) + } + if onlyOneHasArgs(newSyscall, &syscall) { + if firstParamOnlyHasArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i)) + } else { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, nothing) + } + } + } + + if !sameAction(newSyscall, &syscall) { + if bothHaveArgs(newSyscall, &syscall) { + if sameArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i)) + } + if !sameArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend) + } + } + if onlyOneHasArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend) + } + if neitherHasArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i)) + } + } + } + } + + if !ruleForSyscallAlreadyExists { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend) + } + + // Nothing has highest priority + for _, determinedAction := range sliceOfDeterminedActions { + if determinedAction == nothing { + return determinedAction, nil + } + } + + // Overwrite has second highest priority + for _, determinedAction := range sliceOfDeterminedActions { + if strings.Contains(determinedAction, seccompOverwrite) { + return determinedAction, nil + } + } + + // Append has the lowest priority + for _, determinedAction := range sliceOfDeterminedActions { + if determinedAction == seccompAppend { + return determinedAction, nil + } + } + + return "", fmt.Errorf("Trouble determining action: %s", sliceOfDeterminedActions) +} + +func hasArguments(config *rspec.LinuxSyscall) bool { + nilSyscall := new(rspec.LinuxSyscall) + return !sameArgs(nilSyscall, config) +} + +func identical(config1, config2 *rspec.LinuxSyscall) bool { + return reflect.DeepEqual(config1, config2) +} + +func sameName(config1, config2 *rspec.LinuxSyscall) bool { + return reflect.DeepEqual(config1.Names, config2.Names) +} + +func sameAction(config1, config2 *rspec.LinuxSyscall) bool { + return config1.Action == config2.Action +} + +func sameArgs(config1, config2 *rspec.LinuxSyscall) bool { + return reflect.DeepEqual(config1.Args, config2.Args) +} + +func bothHaveArgs(config1, config2 *rspec.LinuxSyscall) bool { + return hasArguments(config1) && hasArguments(config2) +} + +func onlyOneHasArgs(config1, config2 *rspec.LinuxSyscall) bool { + conf1 := hasArguments(config1) + conf2 := hasArguments(config2) + + return (conf1 && !conf2) || (!conf1 && conf2) +} + +func neitherHasArgs(config1, config2 *rspec.LinuxSyscall) bool { + return !hasArguments(config1) && !hasArguments(config2) +} + +func firstParamOnlyHasArgs(config1, config2 *rspec.LinuxSyscall) bool { + return !hasArguments(config1) && hasArguments(config2) +} diff --git a/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate.go b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate.go new file mode 100644 index 00000000..7fa47b77 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate.go @@ -0,0 +1,31 @@ +package capabilities + +import ( + "fmt" + "strings" + + "github.com/syndtr/gocapability/capability" +) + +// CapValid checks whether a capability is valid +func CapValid(c string, hostSpecific bool) error { + isValid := false + + if !strings.HasPrefix(c, "CAP_") { + return fmt.Errorf("capability %s must start with CAP_", c) + } + for _, cap := range capability.List() { + if c == fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())) { + if hostSpecific && cap > LastCap() { + return fmt.Errorf("%s is not supported on the current host", c) + } + isValid = true + break + } + } + + if !isValid { + return fmt.Errorf("invalid capability: %s", c) + } + return nil +} diff --git a/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_linux.go b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_linux.go new file mode 100644 index 00000000..f6cb0d55 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_linux.go @@ -0,0 +1,16 @@ +package capabilities + +import ( + "github.com/syndtr/gocapability/capability" +) + +// LastCap return last cap of system +func LastCap() capability.Cap { + last := capability.CAP_LAST_CAP + // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap + if last == capability.Cap(63) { + last = capability.CAP_BLOCK_SUSPEND + } + + return last +} diff --git a/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_unsupported.go b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_unsupported.go new file mode 100644 index 00000000..e4aed632 --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_unsupported.go @@ -0,0 +1,13 @@ +//go:build !linux +// +build !linux + +package capabilities + +import ( + "github.com/syndtr/gocapability/capability" +) + +// LastCap return last cap of system +func LastCap() capability.Cap { + return capability.Cap(-1) +} diff --git a/vendor/github.com/syndtr/gocapability/LICENSE b/vendor/github.com/syndtr/gocapability/LICENSE new file mode 100644 index 00000000..80dd96de --- /dev/null +++ b/vendor/github.com/syndtr/gocapability/LICENSE @@ -0,0 +1,24 @@ +Copyright 2013 Suryandaru Triandana +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. + +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 +HOLDER 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. diff --git a/vendor/github.com/syndtr/gocapability/capability/capability.go b/vendor/github.com/syndtr/gocapability/capability/capability.go new file mode 100644 index 00000000..61a90775 --- /dev/null +++ b/vendor/github.com/syndtr/gocapability/capability/capability.go @@ -0,0 +1,133 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package capability provides utilities for manipulating POSIX capabilities. +package capability + +type Capabilities interface { + // Get check whether a capability present in the given + // capabilities set. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Get(which CapType, what Cap) bool + + // Empty check whether all capability bits of the given capabilities + // set are zero. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Empty(which CapType) bool + + // Full check whether all capability bits of the given capabilities + // set are one. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Full(which CapType) bool + + // Set sets capabilities of the given capabilities sets. The + // 'which' value should be one or combination (OR'ed) of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Set(which CapType, caps ...Cap) + + // Unset unsets capabilities of the given capabilities sets. The + // 'which' value should be one or combination (OR'ed) of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Unset(which CapType, caps ...Cap) + + // Fill sets all bits of the given capabilities kind to one. The + // 'kind' value should be one or combination (OR'ed) of CAPS, + // BOUNDS or AMBS. + Fill(kind CapType) + + // Clear sets all bits of the given capabilities kind to zero. The + // 'kind' value should be one or combination (OR'ed) of CAPS, + // BOUNDS or AMBS. + Clear(kind CapType) + + // String return current capabilities state of the given capabilities + // set as string. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE BOUNDING or AMBIENT + StringCap(which CapType) string + + // String return current capabilities state as string. + String() string + + // Load load actual capabilities value. This will overwrite all + // outstanding changes. + Load() error + + // Apply apply the capabilities settings, so all changes will take + // effect. + Apply(kind CapType) error +} + +// NewPid initializes a new Capabilities object for given pid when +// it is nonzero, or for the current process if pid is 0. +// +// Deprecated: Replace with NewPid2. For example, replace: +// +// c, err := NewPid(0) +// if err != nil { +// return err +// } +// +// with: +// +// c, err := NewPid2(0) +// if err != nil { +// return err +// } +// err = c.Load() +// if err != nil { +// return err +// } +func NewPid(pid int) (Capabilities, error) { + c, err := newPid(pid) + if err != nil { + return c, err + } + err = c.Load() + return c, err +} + +// NewPid2 initializes a new Capabilities object for given pid when +// it is nonzero, or for the current process if pid is 0. This +// does not load the process's current capabilities; to do that you +// must call Load explicitly. +func NewPid2(pid int) (Capabilities, error) { + return newPid(pid) +} + +// NewFile initializes a new Capabilities object for given file path. +// +// Deprecated: Replace with NewFile2. For example, replace: +// +// c, err := NewFile(path) +// if err != nil { +// return err +// } +// +// with: +// +// c, err := NewFile2(path) +// if err != nil { +// return err +// } +// err = c.Load() +// if err != nil { +// return err +// } +func NewFile(path string) (Capabilities, error) { + c, err := newFile(path) + if err != nil { + return c, err + } + err = c.Load() + return c, err +} + +// NewFile2 creates a new initialized Capabilities object for given +// file path. This does not load the process's current capabilities; +// to do that you must call Load explicitly. +func NewFile2(path string) (Capabilities, error) { + return newFile(path) +} diff --git a/vendor/github.com/syndtr/gocapability/capability/capability_linux.go b/vendor/github.com/syndtr/gocapability/capability/capability_linux.go new file mode 100644 index 00000000..1567dc81 --- /dev/null +++ b/vendor/github.com/syndtr/gocapability/capability/capability_linux.go @@ -0,0 +1,642 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package capability + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "strings" + "syscall" +) + +var errUnknownVers = errors.New("unknown capability version") + +const ( + linuxCapVer1 = 0x19980330 + linuxCapVer2 = 0x20071026 + linuxCapVer3 = 0x20080522 +) + +var ( + capVers uint32 + capLastCap Cap +) + +func init() { + var hdr capHeader + capget(&hdr, nil) + capVers = hdr.version + + if initLastCap() == nil { + CAP_LAST_CAP = capLastCap + if capLastCap > 31 { + capUpperMask = (uint32(1) << (uint(capLastCap) - 31)) - 1 + } else { + capUpperMask = 0 + } + } +} + +func initLastCap() error { + if capLastCap != 0 { + return nil + } + + f, err := os.Open("/proc/sys/kernel/cap_last_cap") + if err != nil { + return err + } + defer f.Close() + + var b []byte = make([]byte, 11) + _, err = f.Read(b) + if err != nil { + return err + } + + fmt.Sscanf(string(b), "%d", &capLastCap) + + return nil +} + +func mkStringCap(c Capabilities, which CapType) (ret string) { + for i, first := Cap(0), true; i <= CAP_LAST_CAP; i++ { + if !c.Get(which, i) { + continue + } + if first { + first = false + } else { + ret += ", " + } + ret += i.String() + } + return +} + +func mkString(c Capabilities, max CapType) (ret string) { + ret = "{" + for i := CapType(1); i <= max; i <<= 1 { + ret += " " + i.String() + "=\"" + if c.Empty(i) { + ret += "empty" + } else if c.Full(i) { + ret += "full" + } else { + ret += c.StringCap(i) + } + ret += "\"" + } + ret += " }" + return +} + +func newPid(pid int) (c Capabilities, err error) { + switch capVers { + case linuxCapVer1: + p := new(capsV1) + p.hdr.version = capVers + p.hdr.pid = int32(pid) + c = p + case linuxCapVer2, linuxCapVer3: + p := new(capsV3) + p.hdr.version = capVers + p.hdr.pid = int32(pid) + c = p + default: + err = errUnknownVers + return + } + return +} + +type capsV1 struct { + hdr capHeader + data capData +} + +func (c *capsV1) Get(which CapType, what Cap) bool { + if what > 32 { + return false + } + + switch which { + case EFFECTIVE: + return (1< 32 { + continue + } + + if which&EFFECTIVE != 0 { + c.data.effective |= 1 << uint(what) + } + if which&PERMITTED != 0 { + c.data.permitted |= 1 << uint(what) + } + if which&INHERITABLE != 0 { + c.data.inheritable |= 1 << uint(what) + } + } +} + +func (c *capsV1) Unset(which CapType, caps ...Cap) { + for _, what := range caps { + if what > 32 { + continue + } + + if which&EFFECTIVE != 0 { + c.data.effective &= ^(1 << uint(what)) + } + if which&PERMITTED != 0 { + c.data.permitted &= ^(1 << uint(what)) + } + if which&INHERITABLE != 0 { + c.data.inheritable &= ^(1 << uint(what)) + } + } +} + +func (c *capsV1) Fill(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective = 0x7fffffff + c.data.permitted = 0x7fffffff + c.data.inheritable = 0 + } +} + +func (c *capsV1) Clear(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective = 0 + c.data.permitted = 0 + c.data.inheritable = 0 + } +} + +func (c *capsV1) StringCap(which CapType) (ret string) { + return mkStringCap(c, which) +} + +func (c *capsV1) String() (ret string) { + return mkString(c, BOUNDING) +} + +func (c *capsV1) Load() (err error) { + return capget(&c.hdr, &c.data) +} + +func (c *capsV1) Apply(kind CapType) error { + if kind&CAPS == CAPS { + return capset(&c.hdr, &c.data) + } + return nil +} + +type capsV3 struct { + hdr capHeader + data [2]capData + bounds [2]uint32 + ambient [2]uint32 +} + +func (c *capsV3) Get(which CapType, what Cap) bool { + var i uint + if what > 31 { + i = uint(what) >> 5 + what %= 32 + } + + switch which { + case EFFECTIVE: + return (1< 31 { + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data[i].effective |= 1 << uint(what) + } + if which&PERMITTED != 0 { + c.data[i].permitted |= 1 << uint(what) + } + if which&INHERITABLE != 0 { + c.data[i].inheritable |= 1 << uint(what) + } + if which&BOUNDING != 0 { + c.bounds[i] |= 1 << uint(what) + } + if which&AMBIENT != 0 { + c.ambient[i] |= 1 << uint(what) + } + } +} + +func (c *capsV3) Unset(which CapType, caps ...Cap) { + for _, what := range caps { + var i uint + if what > 31 { + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data[i].effective &= ^(1 << uint(what)) + } + if which&PERMITTED != 0 { + c.data[i].permitted &= ^(1 << uint(what)) + } + if which&INHERITABLE != 0 { + c.data[i].inheritable &= ^(1 << uint(what)) + } + if which&BOUNDING != 0 { + c.bounds[i] &= ^(1 << uint(what)) + } + if which&AMBIENT != 0 { + c.ambient[i] &= ^(1 << uint(what)) + } + } +} + +func (c *capsV3) Fill(kind CapType) { + if kind&CAPS == CAPS { + c.data[0].effective = 0xffffffff + c.data[0].permitted = 0xffffffff + c.data[0].inheritable = 0 + c.data[1].effective = 0xffffffff + c.data[1].permitted = 0xffffffff + c.data[1].inheritable = 0 + } + + if kind&BOUNDS == BOUNDS { + c.bounds[0] = 0xffffffff + c.bounds[1] = 0xffffffff + } + if kind&AMBS == AMBS { + c.ambient[0] = 0xffffffff + c.ambient[1] = 0xffffffff + } +} + +func (c *capsV3) Clear(kind CapType) { + if kind&CAPS == CAPS { + c.data[0].effective = 0 + c.data[0].permitted = 0 + c.data[0].inheritable = 0 + c.data[1].effective = 0 + c.data[1].permitted = 0 + c.data[1].inheritable = 0 + } + + if kind&BOUNDS == BOUNDS { + c.bounds[0] = 0 + c.bounds[1] = 0 + } + if kind&AMBS == AMBS { + c.ambient[0] = 0 + c.ambient[1] = 0 + } +} + +func (c *capsV3) StringCap(which CapType) (ret string) { + return mkStringCap(c, which) +} + +func (c *capsV3) String() (ret string) { + return mkString(c, BOUNDING) +} + +func (c *capsV3) Load() (err error) { + err = capget(&c.hdr, &c.data[0]) + if err != nil { + return + } + + var status_path string + + if c.hdr.pid == 0 { + status_path = fmt.Sprintf("/proc/self/status") + } else { + status_path = fmt.Sprintf("/proc/%d/status", c.hdr.pid) + } + + f, err := os.Open(status_path) + if err != nil { + return + } + b := bufio.NewReader(f) + for { + line, e := b.ReadString('\n') + if e != nil { + if e != io.EOF { + err = e + } + break + } + if strings.HasPrefix(line, "CapB") { + fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0]) + continue + } + if strings.HasPrefix(line, "CapA") { + fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0]) + continue + } + } + f.Close() + + return +} + +func (c *capsV3) Apply(kind CapType) (err error) { + if kind&BOUNDS == BOUNDS { + var data [2]capData + err = capget(&c.hdr, &data[0]) + if err != nil { + return + } + if (1< 31 { + if c.data.version == 1 { + return false + } + i = uint(what) >> 5 + what %= 32 + } + + switch which { + case EFFECTIVE: + return (1< 31 { + if c.data.version == 1 { + continue + } + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data.effective[i] |= 1 << uint(what) + } + if which&PERMITTED != 0 { + c.data.data[i].permitted |= 1 << uint(what) + } + if which&INHERITABLE != 0 { + c.data.data[i].inheritable |= 1 << uint(what) + } + } +} + +func (c *capsFile) Unset(which CapType, caps ...Cap) { + for _, what := range caps { + var i uint + if what > 31 { + if c.data.version == 1 { + continue + } + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data.effective[i] &= ^(1 << uint(what)) + } + if which&PERMITTED != 0 { + c.data.data[i].permitted &= ^(1 << uint(what)) + } + if which&INHERITABLE != 0 { + c.data.data[i].inheritable &= ^(1 << uint(what)) + } + } +} + +func (c *capsFile) Fill(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective[0] = 0xffffffff + c.data.data[0].permitted = 0xffffffff + c.data.data[0].inheritable = 0 + if c.data.version == 2 { + c.data.effective[1] = 0xffffffff + c.data.data[1].permitted = 0xffffffff + c.data.data[1].inheritable = 0 + } + } +} + +func (c *capsFile) Clear(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective[0] = 0 + c.data.data[0].permitted = 0 + c.data.data[0].inheritable = 0 + if c.data.version == 2 { + c.data.effective[1] = 0 + c.data.data[1].permitted = 0 + c.data.data[1].inheritable = 0 + } + } +} + +func (c *capsFile) StringCap(which CapType) (ret string) { + return mkStringCap(c, which) +} + +func (c *capsFile) String() (ret string) { + return mkString(c, INHERITABLE) +} + +func (c *capsFile) Load() (err error) { + return getVfsCap(c.path, &c.data) +} + +func (c *capsFile) Apply(kind CapType) (err error) { + if kind&CAPS == CAPS { + return setVfsCap(c.path, &c.data) + } + return +} diff --git a/vendor/github.com/syndtr/gocapability/capability/capability_noop.go b/vendor/github.com/syndtr/gocapability/capability/capability_noop.go new file mode 100644 index 00000000..9bb3070c --- /dev/null +++ b/vendor/github.com/syndtr/gocapability/capability/capability_noop.go @@ -0,0 +1,19 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// +build !linux + +package capability + +import "errors" + +func newPid(pid int) (Capabilities, error) { + return nil, errors.New("not supported") +} + +func newFile(path string) (Capabilities, error) { + return nil, errors.New("not supported") +} diff --git a/vendor/github.com/syndtr/gocapability/capability/enum.go b/vendor/github.com/syndtr/gocapability/capability/enum.go new file mode 100644 index 00000000..ad107853 --- /dev/null +++ b/vendor/github.com/syndtr/gocapability/capability/enum.go @@ -0,0 +1,309 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package capability + +type CapType uint + +func (c CapType) String() string { + switch c { + case EFFECTIVE: + return "effective" + case PERMITTED: + return "permitted" + case INHERITABLE: + return "inheritable" + case BOUNDING: + return "bounding" + case CAPS: + return "caps" + case AMBIENT: + return "ambient" + } + return "unknown" +} + +const ( + EFFECTIVE CapType = 1 << iota + PERMITTED + INHERITABLE + BOUNDING + AMBIENT + + CAPS = EFFECTIVE | PERMITTED | INHERITABLE + BOUNDS = BOUNDING + AMBS = AMBIENT +) + +//go:generate go run enumgen/gen.go +type Cap int + +// POSIX-draft defined capabilities and Linux extensions. +// +// Defined in https://github.com/torvalds/linux/blob/master/include/uapi/linux/capability.h +const ( + // In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this + // overrides the restriction of changing file ownership and group + // ownership. + CAP_CHOWN = Cap(0) + + // Override all DAC access, including ACL execute access if + // [_POSIX_ACL] is defined. Excluding DAC access covered by + // CAP_LINUX_IMMUTABLE. + CAP_DAC_OVERRIDE = Cap(1) + + // Overrides all DAC restrictions regarding read and search on files + // and directories, including ACL restrictions if [_POSIX_ACL] is + // defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. + CAP_DAC_READ_SEARCH = Cap(2) + + // Overrides all restrictions about allowed operations on files, where + // file owner ID must be equal to the user ID, except where CAP_FSETID + // is applicable. It doesn't override MAC and DAC restrictions. + CAP_FOWNER = Cap(3) + + // Overrides the following restrictions that the effective user ID + // shall match the file owner ID when setting the S_ISUID and S_ISGID + // bits on that file; that the effective group ID (or one of the + // supplementary group IDs) shall match the file owner ID when setting + // the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are + // cleared on successful return from chown(2) (not implemented). + CAP_FSETID = Cap(4) + + // Overrides the restriction that the real or effective user ID of a + // process sending a signal must match the real or effective user ID + // of the process receiving the signal. + CAP_KILL = Cap(5) + + // Allows setgid(2) manipulation + // Allows setgroups(2) + // Allows forged gids on socket credentials passing. + CAP_SETGID = Cap(6) + + // Allows set*uid(2) manipulation (including fsuid). + // Allows forged pids on socket credentials passing. + CAP_SETUID = Cap(7) + + // Linux-specific capabilities + + // Without VFS support for capabilities: + // Transfer any capability in your permitted set to any pid, + // remove any capability in your permitted set from any pid + // With VFS support for capabilities (neither of above, but) + // Add any capability from current's capability bounding set + // to the current process' inheritable set + // Allow taking bits out of capability bounding set + // Allow modification of the securebits for a process + CAP_SETPCAP = Cap(8) + + // Allow modification of S_IMMUTABLE and S_APPEND file attributes + CAP_LINUX_IMMUTABLE = Cap(9) + + // Allows binding to TCP/UDP sockets below 1024 + // Allows binding to ATM VCIs below 32 + CAP_NET_BIND_SERVICE = Cap(10) + + // Allow broadcasting, listen to multicast + CAP_NET_BROADCAST = Cap(11) + + // Allow interface configuration + // Allow administration of IP firewall, masquerading and accounting + // Allow setting debug option on sockets + // Allow modification of routing tables + // Allow setting arbitrary process / process group ownership on + // sockets + // Allow binding to any address for transparent proxying (also via NET_RAW) + // Allow setting TOS (type of service) + // Allow setting promiscuous mode + // Allow clearing driver statistics + // Allow multicasting + // Allow read/write of device-specific registers + // Allow activation of ATM control sockets + CAP_NET_ADMIN = Cap(12) + + // Allow use of RAW sockets + // Allow use of PACKET sockets + // Allow binding to any address for transparent proxying (also via NET_ADMIN) + CAP_NET_RAW = Cap(13) + + // Allow locking of shared memory segments + // Allow mlock and mlockall (which doesn't really have anything to do + // with IPC) + CAP_IPC_LOCK = Cap(14) + + // Override IPC ownership checks + CAP_IPC_OWNER = Cap(15) + + // Insert and remove kernel modules - modify kernel without limit + CAP_SYS_MODULE = Cap(16) + + // Allow ioperm/iopl access + // Allow sending USB messages to any device via /proc/bus/usb + CAP_SYS_RAWIO = Cap(17) + + // Allow use of chroot() + CAP_SYS_CHROOT = Cap(18) + + // Allow ptrace() of any process + CAP_SYS_PTRACE = Cap(19) + + // Allow configuration of process accounting + CAP_SYS_PACCT = Cap(20) + + // Allow configuration of the secure attention key + // Allow administration of the random device + // Allow examination and configuration of disk quotas + // Allow setting the domainname + // Allow setting the hostname + // Allow calling bdflush() + // Allow mount() and umount(), setting up new smb connection + // Allow some autofs root ioctls + // Allow nfsservctl + // Allow VM86_REQUEST_IRQ + // Allow to read/write pci config on alpha + // Allow irix_prctl on mips (setstacksize) + // Allow flushing all cache on m68k (sys_cacheflush) + // Allow removing semaphores + // Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores + // and shared memory + // Allow locking/unlocking of shared memory segment + // Allow turning swap on/off + // Allow forged pids on socket credentials passing + // Allow setting readahead and flushing buffers on block devices + // Allow setting geometry in floppy driver + // Allow turning DMA on/off in xd driver + // Allow administration of md devices (mostly the above, but some + // extra ioctls) + // Allow tuning the ide driver + // Allow access to the nvram device + // Allow administration of apm_bios, serial and bttv (TV) device + // Allow manufacturer commands in isdn CAPI support driver + // Allow reading non-standardized portions of pci configuration space + // Allow DDI debug ioctl on sbpcd driver + // Allow setting up serial ports + // Allow sending raw qic-117 commands + // Allow enabling/disabling tagged queuing on SCSI controllers and sending + // arbitrary SCSI commands + // Allow setting encryption key on loopback filesystem + // Allow setting zone reclaim policy + // Allow everything under CAP_BPF and CAP_PERFMON for backward compatibility + CAP_SYS_ADMIN = Cap(21) + + // Allow use of reboot() + CAP_SYS_BOOT = Cap(22) + + // Allow raising priority and setting priority on other (different + // UID) processes + // Allow use of FIFO and round-robin (realtime) scheduling on own + // processes and setting the scheduling algorithm used by another + // process. + // Allow setting cpu affinity on other processes + CAP_SYS_NICE = Cap(23) + + // Override resource limits. Set resource limits. + // Override quota limits. + // Override reserved space on ext2 filesystem + // Modify data journaling mode on ext3 filesystem (uses journaling + // resources) + // NOTE: ext2 honors fsuid when checking for resource overrides, so + // you can override using fsuid too + // Override size restrictions on IPC message queues + // Allow more than 64hz interrupts from the real-time clock + // Override max number of consoles on console allocation + // Override max number of keymaps + // Control memory reclaim behavior + CAP_SYS_RESOURCE = Cap(24) + + // Allow manipulation of system clock + // Allow irix_stime on mips + // Allow setting the real-time clock + CAP_SYS_TIME = Cap(25) + + // Allow configuration of tty devices + // Allow vhangup() of tty + CAP_SYS_TTY_CONFIG = Cap(26) + + // Allow the privileged aspects of mknod() + CAP_MKNOD = Cap(27) + + // Allow taking of leases on files + CAP_LEASE = Cap(28) + + CAP_AUDIT_WRITE = Cap(29) + CAP_AUDIT_CONTROL = Cap(30) + CAP_SETFCAP = Cap(31) + + // Override MAC access. + // The base kernel enforces no MAC policy. + // An LSM may enforce a MAC policy, and if it does and it chooses + // to implement capability based overrides of that policy, this is + // the capability it should use to do so. + CAP_MAC_OVERRIDE = Cap(32) + + // Allow MAC configuration or state changes. + // The base kernel requires no MAC configuration. + // An LSM may enforce a MAC policy, and if it does and it chooses + // to implement capability based checks on modifications to that + // policy or the data required to maintain it, this is the + // capability it should use to do so. + CAP_MAC_ADMIN = Cap(33) + + // Allow configuring the kernel's syslog (printk behaviour) + CAP_SYSLOG = Cap(34) + + // Allow triggering something that will wake the system + CAP_WAKE_ALARM = Cap(35) + + // Allow preventing system suspends + CAP_BLOCK_SUSPEND = Cap(36) + + // Allow reading the audit log via multicast netlink socket + CAP_AUDIT_READ = Cap(37) + + // Allow system performance and observability privileged operations + // using perf_events, i915_perf and other kernel subsystems + CAP_PERFMON = Cap(38) + + // CAP_BPF allows the following BPF operations: + // - Creating all types of BPF maps + // - Advanced verifier features + // - Indirect variable access + // - Bounded loops + // - BPF to BPF function calls + // - Scalar precision tracking + // - Larger complexity limits + // - Dead code elimination + // - And potentially other features + // - Loading BPF Type Format (BTF) data + // - Retrieve xlated and JITed code of BPF programs + // - Use bpf_spin_lock() helper + // + // CAP_PERFMON relaxes the verifier checks further: + // - BPF progs can use of pointer-to-integer conversions + // - speculation attack hardening measures are bypassed + // - bpf_probe_read to read arbitrary kernel memory is allowed + // - bpf_trace_printk to print kernel memory is allowed + // + // CAP_SYS_ADMIN is required to use bpf_probe_write_user. + // + // CAP_SYS_ADMIN is required to iterate system wide loaded + // programs, maps, links, BTFs and convert their IDs to file descriptors. + // + // CAP_PERFMON and CAP_BPF are required to load tracing programs. + // CAP_NET_ADMIN and CAP_BPF are required to load networking programs. + CAP_BPF = Cap(39) + + // Allow checkpoint/restore related operations. + // Introduced in kernel 5.9 + CAP_CHECKPOINT_RESTORE = Cap(40) +) + +var ( + // Highest valid capability of the running kernel. + CAP_LAST_CAP = Cap(63) + + capUpperMask = ^uint32(0) +) diff --git a/vendor/github.com/syndtr/gocapability/capability/enum_gen.go b/vendor/github.com/syndtr/gocapability/capability/enum_gen.go new file mode 100644 index 00000000..2ff9bf4d --- /dev/null +++ b/vendor/github.com/syndtr/gocapability/capability/enum_gen.go @@ -0,0 +1,138 @@ +// generated file; DO NOT EDIT - use go generate in directory with source + +package capability + +func (c Cap) String() string { + switch c { + case CAP_CHOWN: + return "chown" + case CAP_DAC_OVERRIDE: + return "dac_override" + case CAP_DAC_READ_SEARCH: + return "dac_read_search" + case CAP_FOWNER: + return "fowner" + case CAP_FSETID: + return "fsetid" + case CAP_KILL: + return "kill" + case CAP_SETGID: + return "setgid" + case CAP_SETUID: + return "setuid" + case CAP_SETPCAP: + return "setpcap" + case CAP_LINUX_IMMUTABLE: + return "linux_immutable" + case CAP_NET_BIND_SERVICE: + return "net_bind_service" + case CAP_NET_BROADCAST: + return "net_broadcast" + case CAP_NET_ADMIN: + return "net_admin" + case CAP_NET_RAW: + return "net_raw" + case CAP_IPC_LOCK: + return "ipc_lock" + case CAP_IPC_OWNER: + return "ipc_owner" + case CAP_SYS_MODULE: + return "sys_module" + case CAP_SYS_RAWIO: + return "sys_rawio" + case CAP_SYS_CHROOT: + return "sys_chroot" + case CAP_SYS_PTRACE: + return "sys_ptrace" + case CAP_SYS_PACCT: + return "sys_pacct" + case CAP_SYS_ADMIN: + return "sys_admin" + case CAP_SYS_BOOT: + return "sys_boot" + case CAP_SYS_NICE: + return "sys_nice" + case CAP_SYS_RESOURCE: + return "sys_resource" + case CAP_SYS_TIME: + return "sys_time" + case CAP_SYS_TTY_CONFIG: + return "sys_tty_config" + case CAP_MKNOD: + return "mknod" + case CAP_LEASE: + return "lease" + case CAP_AUDIT_WRITE: + return "audit_write" + case CAP_AUDIT_CONTROL: + return "audit_control" + case CAP_SETFCAP: + return "setfcap" + case CAP_MAC_OVERRIDE: + return "mac_override" + case CAP_MAC_ADMIN: + return "mac_admin" + case CAP_SYSLOG: + return "syslog" + case CAP_WAKE_ALARM: + return "wake_alarm" + case CAP_BLOCK_SUSPEND: + return "block_suspend" + case CAP_AUDIT_READ: + return "audit_read" + case CAP_PERFMON: + return "perfmon" + case CAP_BPF: + return "bpf" + case CAP_CHECKPOINT_RESTORE: + return "checkpoint_restore" + } + return "unknown" +} + +// List returns list of all supported capabilities +func List() []Cap { + return []Cap{ + CAP_CHOWN, + CAP_DAC_OVERRIDE, + CAP_DAC_READ_SEARCH, + CAP_FOWNER, + CAP_FSETID, + CAP_KILL, + CAP_SETGID, + CAP_SETUID, + CAP_SETPCAP, + CAP_LINUX_IMMUTABLE, + CAP_NET_BIND_SERVICE, + CAP_NET_BROADCAST, + CAP_NET_ADMIN, + CAP_NET_RAW, + CAP_IPC_LOCK, + CAP_IPC_OWNER, + CAP_SYS_MODULE, + CAP_SYS_RAWIO, + CAP_SYS_CHROOT, + CAP_SYS_PTRACE, + CAP_SYS_PACCT, + CAP_SYS_ADMIN, + CAP_SYS_BOOT, + CAP_SYS_NICE, + CAP_SYS_RESOURCE, + CAP_SYS_TIME, + CAP_SYS_TTY_CONFIG, + CAP_MKNOD, + CAP_LEASE, + CAP_AUDIT_WRITE, + CAP_AUDIT_CONTROL, + CAP_SETFCAP, + CAP_MAC_OVERRIDE, + CAP_MAC_ADMIN, + CAP_SYSLOG, + CAP_WAKE_ALARM, + CAP_BLOCK_SUSPEND, + CAP_AUDIT_READ, + CAP_PERFMON, + CAP_BPF, + CAP_CHECKPOINT_RESTORE, + } +} diff --git a/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go b/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go new file mode 100644 index 00000000..3d2bf692 --- /dev/null +++ b/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go @@ -0,0 +1,154 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package capability + +import ( + "syscall" + "unsafe" +) + +type capHeader struct { + version uint32 + pid int32 +} + +type capData struct { + effective uint32 + permitted uint32 + inheritable uint32 +} + +func capget(hdr *capHeader, data *capData) (err error) { + _, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = e1 + } + return +} + +func capset(hdr *capHeader, data *capData) (err error) { + _, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = e1 + } + return +} + +// not yet in syscall +const ( + pr_CAP_AMBIENT = 47 + pr_CAP_AMBIENT_IS_SET = uintptr(1) + pr_CAP_AMBIENT_RAISE = uintptr(2) + pr_CAP_AMBIENT_LOWER = uintptr(3) + pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4) +) + +func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) { + _, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0) + if e1 != 0 { + err = e1 + } + return +} + +const ( + vfsXattrName = "security.capability" + + vfsCapVerMask = 0xff000000 + vfsCapVer1 = 0x01000000 + vfsCapVer2 = 0x02000000 + + vfsCapFlagMask = ^vfsCapVerMask + vfsCapFlageffective = 0x000001 + + vfscapDataSizeV1 = 4 * (1 + 2*1) + vfscapDataSizeV2 = 4 * (1 + 2*2) +) + +type vfscapData struct { + magic uint32 + data [2]struct { + permitted uint32 + inheritable uint32 + } + effective [2]uint32 + version int8 +} + +var ( + _vfsXattrName *byte +) + +func init() { + _vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName) +} + +func getVfsCap(path string, dest *vfscapData) (err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0) + if e1 != 0 { + if e1 == syscall.ENODATA { + dest.version = 2 + return + } + err = e1 + } + switch dest.magic & vfsCapVerMask { + case vfsCapVer1: + dest.version = 1 + if r0 != vfscapDataSizeV1 { + return syscall.EINVAL + } + dest.data[1].permitted = 0 + dest.data[1].inheritable = 0 + case vfsCapVer2: + dest.version = 2 + if r0 != vfscapDataSizeV2 { + return syscall.EINVAL + } + default: + return syscall.EINVAL + } + if dest.magic&vfsCapFlageffective != 0 { + dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable + dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable + } else { + dest.effective[0] = 0 + dest.effective[1] = 0 + } + return +} + +func setVfsCap(path string, data *vfscapData) (err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(path) + if err != nil { + return + } + var size uintptr + if data.version == 1 { + data.magic = vfsCapVer1 + size = vfscapDataSizeV1 + } else if data.version == 2 { + data.magic = vfsCapVer2 + if data.effective[0] != 0 || data.effective[1] != 0 { + data.magic |= vfsCapFlageffective + } + size = vfscapDataSizeV2 + } else { + return syscall.EINVAL + } + _, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0) + if e1 != 0 { + err = e1 + } + return +} diff --git a/vendor/golang.org/x/mod/LICENSE b/vendor/golang.org/x/mod/LICENSE new file mode 100644 index 00000000..2a7cf70d --- /dev/null +++ b/vendor/golang.org/x/mod/LICENSE @@ -0,0 +1,27 @@ +Copyright 2009 The Go Authors. + +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 LLC 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. diff --git a/vendor/golang.org/x/mod/PATENTS b/vendor/golang.org/x/mod/PATENTS new file mode 100644 index 00000000..73309904 --- /dev/null +++ b/vendor/golang.org/x/mod/PATENTS @@ -0,0 +1,22 @@ +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. diff --git a/vendor/golang.org/x/mod/semver/semver.go b/vendor/golang.org/x/mod/semver/semver.go new file mode 100644 index 00000000..628f8fd6 --- /dev/null +++ b/vendor/golang.org/x/mod/semver/semver.go @@ -0,0 +1,407 @@ +// 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. + +// Package semver implements comparison of semantic version strings. +// In this package, semantic version strings must begin with a leading "v", +// as in "v1.0.0". +// +// The general form of a semantic version string accepted by this package is +// +// vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]] +// +// where square brackets indicate optional parts of the syntax; +// MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros; +// PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers +// using only alphanumeric characters and hyphens; and +// all-numeric PRERELEASE identifiers must not have leading zeros. +// +// This package follows Semantic Versioning 2.0.0 (see semver.org) +// with two exceptions. First, it requires the "v" prefix. Second, it recognizes +// vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes) +// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0. +package semver + +import ( + "slices" + "strings" +) + +// parsed returns the parsed form of a semantic version string. +type parsed struct { + major string + minor string + patch string + short string + prerelease string + build string +} + +// IsValid reports whether v is a valid semantic version string. +func IsValid(v string) bool { + _, ok := parse(v) + return ok +} + +// Canonical returns the canonical formatting of the semantic version v. +// It fills in any missing .MINOR or .PATCH and discards build metadata. +// Two semantic versions compare equal only if their canonical formattings +// are identical strings. +// The canonical invalid semantic version is the empty string. +func Canonical(v string) string { + p, ok := parse(v) + if !ok { + return "" + } + if p.build != "" { + return v[:len(v)-len(p.build)] + } + if p.short != "" { + return v + p.short + } + return v +} + +// Major returns the major version prefix of the semantic version v. +// For example, Major("v2.1.0") == "v2". +// If v is an invalid semantic version string, Major returns the empty string. +func Major(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + return v[:1+len(pv.major)] +} + +// MajorMinor returns the major.minor version prefix of the semantic version v. +// For example, MajorMinor("v2.1.0") == "v2.1". +// If v is an invalid semantic version string, MajorMinor returns the empty string. +func MajorMinor(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + i := 1 + len(pv.major) + if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor { + return v[:j] + } + return v[:i] + "." + pv.minor +} + +// Prerelease returns the prerelease suffix of the semantic version v. +// For example, Prerelease("v2.1.0-pre+meta") == "-pre". +// If v is an invalid semantic version string, Prerelease returns the empty string. +func Prerelease(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + return pv.prerelease +} + +// Build returns the build suffix of the semantic version v. +// For example, Build("v2.1.0+meta") == "+meta". +// If v is an invalid semantic version string, Build returns the empty string. +func Build(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + return pv.build +} + +// Compare returns an integer comparing two versions according to +// semantic version precedence. +// The result will be 0 if v == w, -1 if v < w, or +1 if v > w. +// +// An invalid semantic version string is considered less than a valid one. +// All invalid semantic version strings compare equal to each other. +func Compare(v, w string) int { + pv, ok1 := parse(v) + pw, ok2 := parse(w) + if !ok1 && !ok2 { + return 0 + } + if !ok1 { + return -1 + } + if !ok2 { + return +1 + } + if c := compareInt(pv.major, pw.major); c != 0 { + return c + } + if c := compareInt(pv.minor, pw.minor); c != 0 { + return c + } + if c := compareInt(pv.patch, pw.patch); c != 0 { + return c + } + return comparePrerelease(pv.prerelease, pw.prerelease) +} + +// Max canonicalizes its arguments and then returns the version string +// that compares greater. +// +// Deprecated: use [Compare] instead. In most cases, returning a canonicalized +// version is not expected or desired. +func Max(v, w string) string { + v = Canonical(v) + w = Canonical(w) + if Compare(v, w) > 0 { + return v + } + return w +} + +// ByVersion implements [sort.Interface] for sorting semantic version strings. +type ByVersion []string + +func (vs ByVersion) Len() int { return len(vs) } +func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] } +func (vs ByVersion) Less(i, j int) bool { return compareVersion(vs[i], vs[j]) < 0 } + +// Sort sorts a list of semantic version strings using [Compare] and falls back +// to use [strings.Compare] if both versions are considered equal. +func Sort(list []string) { + slices.SortFunc(list, compareVersion) +} + +func compareVersion(a, b string) int { + cmp := Compare(a, b) + if cmp != 0 { + return cmp + } + return strings.Compare(a, b) +} + +func parse(v string) (p parsed, ok bool) { + if v == "" || v[0] != 'v' { + return + } + p.major, v, ok = parseInt(v[1:]) + if !ok { + return + } + if v == "" { + p.minor = "0" + p.patch = "0" + p.short = ".0.0" + return + } + if v[0] != '.' { + ok = false + return + } + p.minor, v, ok = parseInt(v[1:]) + if !ok { + return + } + if v == "" { + p.patch = "0" + p.short = ".0" + return + } + if v[0] != '.' { + ok = false + return + } + p.patch, v, ok = parseInt(v[1:]) + if !ok { + return + } + if len(v) > 0 && v[0] == '-' { + p.prerelease, v, ok = parsePrerelease(v) + if !ok { + return + } + } + if len(v) > 0 && v[0] == '+' { + p.build, v, ok = parseBuild(v) + if !ok { + return + } + } + if v != "" { + ok = false + return + } + ok = true + return +} + +func parseInt(v string) (t, rest string, ok bool) { + if v == "" { + return + } + if v[0] < '0' || '9' < v[0] { + return + } + i := 1 + for i < len(v) && '0' <= v[i] && v[i] <= '9' { + i++ + } + if v[0] == '0' && i != 1 { + return + } + return v[:i], v[i:], true +} + +func parsePrerelease(v string) (t, rest string, ok bool) { + // "A pre-release version MAY be denoted by appending a hyphen and + // a series of dot separated identifiers immediately following the patch version. + // Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. + // Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes." + if v == "" || v[0] != '-' { + return + } + i := 1 + start := 1 + for i < len(v) && v[i] != '+' { + if !isIdentChar(v[i]) && v[i] != '.' { + return + } + if v[i] == '.' { + if start == i || isBadNum(v[start:i]) { + return + } + start = i + 1 + } + i++ + } + if start == i || isBadNum(v[start:i]) { + return + } + return v[:i], v[i:], true +} + +func parseBuild(v string) (t, rest string, ok bool) { + if v == "" || v[0] != '+' { + return + } + i := 1 + start := 1 + for i < len(v) { + if !isIdentChar(v[i]) && v[i] != '.' { + return + } + if v[i] == '.' { + if start == i { + return + } + start = i + 1 + } + i++ + } + if start == i { + return + } + return v[:i], v[i:], true +} + +func isIdentChar(c byte) bool { + return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-' +} + +func isBadNum(v string) bool { + i := 0 + for i < len(v) && '0' <= v[i] && v[i] <= '9' { + i++ + } + return i == len(v) && i > 1 && v[0] == '0' +} + +func isNum(v string) bool { + i := 0 + for i < len(v) && '0' <= v[i] && v[i] <= '9' { + i++ + } + return i == len(v) +} + +func compareInt(x, y string) int { + if x == y { + return 0 + } + if len(x) < len(y) { + return -1 + } + if len(x) > len(y) { + return +1 + } + if x < y { + return -1 + } else { + return +1 + } +} + +func comparePrerelease(x, y string) int { + // "When major, minor, and patch are equal, a pre-release version has + // lower precedence than a normal version. + // Example: 1.0.0-alpha < 1.0.0. + // Precedence for two pre-release versions with the same major, minor, + // and patch version MUST be determined by comparing each dot separated + // identifier from left to right until a difference is found as follows: + // identifiers consisting of only digits are compared numerically and + // identifiers with letters or hyphens are compared lexically in ASCII + // sort order. Numeric identifiers always have lower precedence than + // non-numeric identifiers. A larger set of pre-release fields has a + // higher precedence than a smaller set, if all of the preceding + // identifiers are equal. + // Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < + // 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0." + if x == y { + return 0 + } + if x == "" { + return +1 + } + if y == "" { + return -1 + } + for x != "" && y != "" { + x = x[1:] // skip - or . + y = y[1:] // skip - or . + var dx, dy string + dx, x = nextIdent(x) + dy, y = nextIdent(y) + if dx != dy { + ix := isNum(dx) + iy := isNum(dy) + if ix != iy { + if ix { + return -1 + } else { + return +1 + } + } + if ix { + if len(dx) < len(dy) { + return -1 + } + if len(dx) > len(dy) { + return +1 + } + } + if dx < dy { + return -1 + } else { + return +1 + } + } + } + if x == "" { + return -1 + } else { + return +1 + } +} + +func nextIdent(x string) (dx, rest string) { + i := 0 + for i < len(x) && x[i] != '.' { + i++ + } + return x[:i], x[i:] +} diff --git a/vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go b/vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go deleted file mode 100644 index 73687de7..00000000 --- a/vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go +++ /dev/null @@ -1,21 +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. - -//go:build go1.5 - -package plan9 - -import "syscall" - -func fixwd() { - syscall.Fixwd() -} - -func Getwd() (wd string, err error) { - return syscall.Getwd() -} - -func Chdir(path string) error { - return syscall.Chdir(path) -} diff --git a/vendor/golang.org/x/sys/plan9/pwd_plan9.go b/vendor/golang.org/x/sys/plan9/pwd_plan9.go index fb945821..7a76489d 100644 --- a/vendor/golang.org/x/sys/plan9/pwd_plan9.go +++ b/vendor/golang.org/x/sys/plan9/pwd_plan9.go @@ -2,22 +2,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !go1.5 - package plan9 +import "syscall" + func fixwd() { + syscall.Fixwd() } func Getwd() (wd string, err error) { - fd, err := open(".", O_RDONLY) - if err != nil { - return "", err - } - defer Close(fd) - return Fd2path(fd) + return syscall.Getwd() } func Chdir(path string) error { - return chdir(path) + return syscall.Chdir(path) } diff --git a/vendor/golang.org/x/sys/unix/affinity_linux.go b/vendor/golang.org/x/sys/unix/affinity_linux.go index 6e5c81ac..3ea47038 100644 --- a/vendor/golang.org/x/sys/unix/affinity_linux.go +++ b/vendor/golang.org/x/sys/unix/affinity_linux.go @@ -38,8 +38,15 @@ func SchedSetaffinity(pid int, set *CPUSet) error { // Zero clears the set s, so that it contains no CPUs. func (s *CPUSet) Zero() { + clear(s[:]) +} + +// Fill adds all possible CPU bits to the set s. On Linux, [SchedSetaffinity] +// will silently ignore any invalid CPU bits in [CPUSet] so this is an +// efficient way of resetting the CPU affinity of a process. +func (s *CPUSet) Fill() { for i := range s { - s[i] = 0 + s[i] = ^cpuMask(0) } } diff --git a/vendor/golang.org/x/sys/unix/fdset.go b/vendor/golang.org/x/sys/unix/fdset.go index 9e83d18c..62ed1264 100644 --- a/vendor/golang.org/x/sys/unix/fdset.go +++ b/vendor/golang.org/x/sys/unix/fdset.go @@ -23,7 +23,5 @@ func (fds *FdSet) IsSet(fd int) bool { // Zero clears the set fds. func (fds *FdSet) Zero() { - for i := range fds.Bits { - fds.Bits[i] = 0 - } + clear(fds.Bits[:]) } diff --git a/vendor/golang.org/x/sys/unix/ifreq_linux.go b/vendor/golang.org/x/sys/unix/ifreq_linux.go index 848840ae..309f5a2b 100644 --- a/vendor/golang.org/x/sys/unix/ifreq_linux.go +++ b/vendor/golang.org/x/sys/unix/ifreq_linux.go @@ -111,9 +111,7 @@ func (ifr *Ifreq) SetUint32(v uint32) { // clear zeroes the ifreq's union field to prevent trailing garbage data from // being sent to the kernel if an ifreq is reused. func (ifr *Ifreq) clear() { - for i := range ifr.raw.Ifru { - ifr.raw.Ifru[i] = 0 - } + clear(ifr.raw.Ifru[:]) } // TODO(mdlayher): export as IfreqData? For now we can provide helpers such as diff --git a/vendor/golang.org/x/sys/unix/mkall.sh b/vendor/golang.org/x/sys/unix/mkall.sh index e6f31d37..d0ed6119 100644 --- a/vendor/golang.org/x/sys/unix/mkall.sh +++ b/vendor/golang.org/x/sys/unix/mkall.sh @@ -49,6 +49,7 @@ esac if [[ "$GOOS" = "linux" ]]; then # Use the Docker-based build system # Files generated through docker (use $cmd so you can Ctl-C the build or run) + set -e $cmd docker build --tag generate:$GOOS $GOOS $cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS exit diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index 6ab02b6c..d1c8b264 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -349,6 +349,9 @@ struct ltchars { #define _HIDIOCGRAWPHYS HIDIOCGRAWPHYS(_HIDIOCGRAWPHYS_LEN) #define _HIDIOCGRAWUNIQ HIDIOCGRAWUNIQ(_HIDIOCGRAWUNIQ_LEN) +// Renamed in v6.16, commit c6d732c38f93 ("net: ethtool: remove duplicate defines for family info") +#define ETHTOOL_FAMILY_NAME ETHTOOL_GENL_NAME +#define ETHTOOL_FAMILY_VERSION ETHTOOL_GENL_VERSION ' includes_NetBSD=' diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index 099867de..7838ca5d 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -602,6 +602,95 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI return } +const minIovec = 8 + +func Readv(fd int, iovs [][]byte) (n int, err error) { + iovecs := make([]Iovec, 0, minIovec) + iovecs = appendBytes(iovecs, iovs) + n, err = readv(fd, iovecs) + readvRacedetect(iovecs, n, err) + return n, err +} + +func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) { + iovecs := make([]Iovec, 0, minIovec) + iovecs = appendBytes(iovecs, iovs) + n, err = preadv(fd, iovecs, offset) + readvRacedetect(iovecs, n, err) + return n, err +} + +func Writev(fd int, iovs [][]byte) (n int, err error) { + iovecs := make([]Iovec, 0, minIovec) + iovecs = appendBytes(iovecs, iovs) + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + n, err = writev(fd, iovecs) + writevRacedetect(iovecs, n) + return n, err +} + +func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) { + iovecs := make([]Iovec, 0, minIovec) + iovecs = appendBytes(iovecs, iovs) + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + n, err = pwritev(fd, iovecs, offset) + writevRacedetect(iovecs, n) + return n, err +} + +func appendBytes(vecs []Iovec, bs [][]byte) []Iovec { + for _, b := range bs { + var v Iovec + v.SetLen(len(b)) + if len(b) > 0 { + v.Base = &b[0] + } else { + v.Base = (*byte)(unsafe.Pointer(&_zero)) + } + vecs = append(vecs, v) + } + return vecs +} + +func writevRacedetect(iovecs []Iovec, n int) { + if !raceenabled { + return + } + for i := 0; n > 0 && i < len(iovecs); i++ { + m := int(iovecs[i].Len) + if m > n { + m = n + } + n -= m + if m > 0 { + raceReadRange(unsafe.Pointer(iovecs[i].Base), m) + } + } +} + +func readvRacedetect(iovecs []Iovec, n int, err error) { + if !raceenabled { + return + } + for i := 0; n > 0 && i < len(iovecs); i++ { + m := int(iovecs[i].Len) + if m > n { + m = n + } + n -= m + if m > 0 { + raceWriteRange(unsafe.Pointer(iovecs[i].Base), m) + } + } + if err == nil { + raceAcquire(unsafe.Pointer(&ioSync)) + } +} + //sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error) //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) @@ -705,3 +794,7 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI //sys write(fd int, p []byte) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) //sys munmap(addr uintptr, length uintptr) (err error) +//sys readv(fd int, iovecs []Iovec) (n int, err error) +//sys preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) +//sys writev(fd int, iovecs []Iovec) (n int, err error) +//sys pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index 230a9454..9439af96 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -13,6 +13,7 @@ package unix import ( "encoding/binary" + "slices" "strconv" "syscall" "time" @@ -417,7 +418,7 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) { return nil, 0, EINVAL } sa.raw.Family = AF_UNIX - for i := 0; i < n; i++ { + for i := range n { sa.raw.Path[i] = int8(name[i]) } // length is family (uint16), name, NUL. @@ -507,7 +508,7 @@ func (sa *SockaddrL2) sockaddr() (unsafe.Pointer, _Socklen, error) { psm := (*[2]byte)(unsafe.Pointer(&sa.raw.Psm)) psm[0] = byte(sa.PSM) psm[1] = byte(sa.PSM >> 8) - for i := 0; i < len(sa.Addr); i++ { + for i := range len(sa.Addr) { sa.raw.Bdaddr[i] = sa.Addr[len(sa.Addr)-1-i] } cid := (*[2]byte)(unsafe.Pointer(&sa.raw.Cid)) @@ -589,11 +590,11 @@ func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, _Socklen, error) { sa.raw.Family = AF_CAN sa.raw.Ifindex = int32(sa.Ifindex) rx := (*[4]byte)(unsafe.Pointer(&sa.RxID)) - for i := 0; i < 4; i++ { + for i := range 4 { sa.raw.Addr[i] = rx[i] } tx := (*[4]byte)(unsafe.Pointer(&sa.TxID)) - for i := 0; i < 4; i++ { + for i := range 4 { sa.raw.Addr[i+4] = tx[i] } return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil @@ -618,11 +619,11 @@ func (sa *SockaddrCANJ1939) sockaddr() (unsafe.Pointer, _Socklen, error) { sa.raw.Family = AF_CAN sa.raw.Ifindex = int32(sa.Ifindex) n := (*[8]byte)(unsafe.Pointer(&sa.Name)) - for i := 0; i < 8; i++ { + for i := range 8 { sa.raw.Addr[i] = n[i] } p := (*[4]byte)(unsafe.Pointer(&sa.PGN)) - for i := 0; i < 4; i++ { + for i := range 4 { sa.raw.Addr[i+8] = p[i] } sa.raw.Addr[12] = sa.Addr @@ -800,9 +801,7 @@ func (sa *SockaddrPPPoE) sockaddr() (unsafe.Pointer, _Socklen, error) { // one. The kernel expects SID to be in network byte order. binary.BigEndian.PutUint16(sa.raw[6:8], sa.SID) copy(sa.raw[8:14], sa.Remote) - for i := 14; i < 14+IFNAMSIZ; i++ { - sa.raw[i] = 0 - } + clear(sa.raw[14 : 14+IFNAMSIZ]) copy(sa.raw[14:], sa.Dev) return unsafe.Pointer(&sa.raw), SizeofSockaddrPPPoX, nil } @@ -911,7 +910,7 @@ func (sa *SockaddrIUCV) sockaddr() (unsafe.Pointer, _Socklen, error) { // These are EBCDIC encoded by the kernel, but we still need to pad them // with blanks. Initializing with blanks allows the caller to feed in either // a padded or an unpadded string. - for i := 0; i < 8; i++ { + for i := range 8 { sa.raw.Nodeid[i] = ' ' sa.raw.User_id[i] = ' ' sa.raw.Name[i] = ' ' @@ -1148,7 +1147,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { var user [8]byte var name [8]byte - for i := 0; i < 8; i++ { + for i := range 8 { user[i] = byte(pp.User_id[i]) name[i] = byte(pp.Name[i]) } @@ -1173,11 +1172,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { Ifindex: int(pp.Ifindex), } name := (*[8]byte)(unsafe.Pointer(&sa.Name)) - for i := 0; i < 8; i++ { + for i := range 8 { name[i] = pp.Addr[i] } pgn := (*[4]byte)(unsafe.Pointer(&sa.PGN)) - for i := 0; i < 4; i++ { + for i := range 4 { pgn[i] = pp.Addr[i+8] } addr := (*[1]byte)(unsafe.Pointer(&sa.Addr)) @@ -1188,11 +1187,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { Ifindex: int(pp.Ifindex), } rx := (*[4]byte)(unsafe.Pointer(&sa.RxID)) - for i := 0; i < 4; i++ { + for i := range 4 { rx[i] = pp.Addr[i] } tx := (*[4]byte)(unsafe.Pointer(&sa.TxID)) - for i := 0; i < 4; i++ { + for i := range 4 { tx[i] = pp.Addr[i+4] } return sa, nil @@ -2216,10 +2215,7 @@ func readvRacedetect(iovecs []Iovec, n int, err error) { return } for i := 0; n > 0 && i < len(iovecs); i++ { - m := int(iovecs[i].Len) - if m > n { - m = n - } + m := min(int(iovecs[i].Len), n) n -= m if m > 0 { raceWriteRange(unsafe.Pointer(iovecs[i].Base), m) @@ -2270,10 +2266,7 @@ func writevRacedetect(iovecs []Iovec, n int) { return } for i := 0; n > 0 && i < len(iovecs); i++ { - m := int(iovecs[i].Len) - if m > n { - m = n - } + m := min(int(iovecs[i].Len), n) n -= m if m > 0 { raceReadRange(unsafe.Pointer(iovecs[i].Base), m) @@ -2320,12 +2313,7 @@ func isGroupMember(gid int) bool { return false } - for _, g := range groups { - if g == gid { - return true - } - } - return false + return slices.Contains(groups, gid) } func isCapDacOverrideSet() bool { diff --git a/vendor/golang.org/x/sys/unix/syscall_netbsd.go b/vendor/golang.org/x/sys/unix/syscall_netbsd.go index 88162099..34a46769 100644 --- a/vendor/golang.org/x/sys/unix/syscall_netbsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_netbsd.go @@ -248,6 +248,23 @@ func Statvfs(path string, buf *Statvfs_t) (err error) { return Statvfs1(path, buf, ST_WAIT) } +func Getvfsstat(buf []Statvfs_t, flags int) (n int, err error) { + var ( + _p0 unsafe.Pointer + bufsize uintptr + ) + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + bufsize = unsafe.Sizeof(Statvfs_t{}) * uintptr(len(buf)) + } + r0, _, e1 := Syscall(SYS_GETVFSSTAT, uintptr(_p0), bufsize, uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = e1 + } + return +} + /* * Exposed directly */ diff --git a/vendor/golang.org/x/sys/unix/syscall_solaris.go b/vendor/golang.org/x/sys/unix/syscall_solaris.go index abc39554..18a3d9bd 100644 --- a/vendor/golang.org/x/sys/unix/syscall_solaris.go +++ b/vendor/golang.org/x/sys/unix/syscall_solaris.go @@ -629,7 +629,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e //sys Kill(pid int, signum syscall.Signal) (err error) //sys Lchown(path string, uid int, gid int) (err error) //sys Link(path string, link string) (err error) -//sys Listen(s int, backlog int) (err error) = libsocket.__xnet_llisten +//sys Listen(s int, backlog int) (err error) = libsocket.__xnet_listen //sys Lstat(path string, stat *Stat_t) (err error) //sys Madvise(b []byte, advice int) (err error) //sys Mkdir(path string, mode uint32) (err error) diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index 4f432bfe..b6db27d9 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -319,6 +319,7 @@ const ( AUDIT_INTEGRITY_POLICY_RULE = 0x70f AUDIT_INTEGRITY_RULE = 0x70d AUDIT_INTEGRITY_STATUS = 0x70a + AUDIT_INTEGRITY_USERSPACE = 0x710 AUDIT_IPC = 0x517 AUDIT_IPC_SET_PERM = 0x51f AUDIT_IPE_ACCESS = 0x58c @@ -327,6 +328,8 @@ const ( AUDIT_KERNEL = 0x7d0 AUDIT_KERNEL_OTHER = 0x524 AUDIT_KERN_MODULE = 0x532 + AUDIT_LANDLOCK_ACCESS = 0x58f + AUDIT_LANDLOCK_DOMAIN = 0x590 AUDIT_LAST_FEATURE = 0x1 AUDIT_LAST_KERN_ANOM_MSG = 0x707 AUDIT_LAST_USER_MSG = 0x4af @@ -491,6 +494,7 @@ const ( BPF_F_BEFORE = 0x8 BPF_F_ID = 0x20 BPF_F_NETFILTER_IP_DEFRAG = 0x1 + BPF_F_PREORDER = 0x40 BPF_F_QUERY_EFFECTIVE = 0x1 BPF_F_REDIRECT_FLAGS = 0x19 BPF_F_REPLACE = 0x4 @@ -527,6 +531,7 @@ const ( BPF_LDX = 0x1 BPF_LEN = 0x80 BPF_LL_OFF = -0x200000 + BPF_LOAD_ACQ = 0x100 BPF_LSH = 0x60 BPF_MAJOR_VERSION = 0x1 BPF_MAXINSNS = 0x1000 @@ -554,6 +559,7 @@ const ( BPF_RET = 0x6 BPF_RSH = 0x70 BPF_ST = 0x2 + BPF_STORE_REL = 0x110 BPF_STX = 0x3 BPF_SUB = 0x10 BPF_TAG_SIZE = 0x8 @@ -843,9 +849,9 @@ const ( DM_UUID_FLAG = 0x4000 DM_UUID_LEN = 0x81 DM_VERSION = 0xc138fd00 - DM_VERSION_EXTRA = "-ioctl (2023-03-01)" + DM_VERSION_EXTRA = "-ioctl (2025-04-28)" DM_VERSION_MAJOR = 0x4 - DM_VERSION_MINOR = 0x30 + DM_VERSION_MINOR = 0x32 DM_VERSION_PATCHLEVEL = 0x0 DT_BLK = 0x6 DT_CHR = 0x2 @@ -936,11 +942,10 @@ const ( EPOLL_CTL_MOD = 0x3 EPOLL_IOC_TYPE = 0x8a EROFS_SUPER_MAGIC_V1 = 0xe0f5e1e2 - ESP_V4_FLOW = 0xa - ESP_V6_FLOW = 0xc - ETHER_FLOW = 0x12 ETHTOOL_BUSINFO_LEN = 0x20 ETHTOOL_EROMVERS_LEN = 0x20 + ETHTOOL_FAMILY_NAME = "ethtool" + ETHTOOL_FAMILY_VERSION = 0x1 ETHTOOL_FEC_AUTO = 0x2 ETHTOOL_FEC_BASER = 0x10 ETHTOOL_FEC_LLRS = 0x20 @@ -1203,13 +1208,18 @@ const ( FAN_DENY = 0x2 FAN_ENABLE_AUDIT = 0x40 FAN_EPIDFD = -0x2 + FAN_ERRNO_BITS = 0x8 + FAN_ERRNO_MASK = 0xff + FAN_ERRNO_SHIFT = 0x18 FAN_EVENT_INFO_TYPE_DFID = 0x3 FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2 FAN_EVENT_INFO_TYPE_ERROR = 0x5 FAN_EVENT_INFO_TYPE_FID = 0x1 + FAN_EVENT_INFO_TYPE_MNT = 0x7 FAN_EVENT_INFO_TYPE_NEW_DFID_NAME = 0xc FAN_EVENT_INFO_TYPE_OLD_DFID_NAME = 0xa FAN_EVENT_INFO_TYPE_PIDFD = 0x4 + FAN_EVENT_INFO_TYPE_RANGE = 0x6 FAN_EVENT_METADATA_LEN = 0x18 FAN_EVENT_ON_CHILD = 0x8000000 FAN_FS_ERROR = 0x8000 @@ -1224,9 +1234,12 @@ const ( FAN_MARK_IGNORED_SURV_MODIFY = 0x40 FAN_MARK_IGNORE_SURV = 0x440 FAN_MARK_INODE = 0x0 + FAN_MARK_MNTNS = 0x110 FAN_MARK_MOUNT = 0x10 FAN_MARK_ONLYDIR = 0x8 FAN_MARK_REMOVE = 0x2 + FAN_MNT_ATTACH = 0x1000000 + FAN_MNT_DETACH = 0x2000000 FAN_MODIFY = 0x2 FAN_MOVE = 0xc0 FAN_MOVED_FROM = 0x40 @@ -1240,6 +1253,7 @@ const ( FAN_OPEN_EXEC = 0x1000 FAN_OPEN_EXEC_PERM = 0x40000 FAN_OPEN_PERM = 0x10000 + FAN_PRE_ACCESS = 0x100000 FAN_Q_OVERFLOW = 0x4000 FAN_RENAME = 0x10000000 FAN_REPORT_DFID_NAME = 0xc00 @@ -1247,6 +1261,7 @@ const ( FAN_REPORT_DIR_FID = 0x400 FAN_REPORT_FD_ERROR = 0x2000 FAN_REPORT_FID = 0x200 + FAN_REPORT_MNT = 0x4000 FAN_REPORT_NAME = 0x800 FAN_REPORT_PIDFD = 0x80 FAN_REPORT_TARGET_FID = 0x1000 @@ -1266,6 +1281,7 @@ const ( FIB_RULE_PERMANENT = 0x1 FIB_RULE_UNRESOLVED = 0x4 FIDEDUPERANGE = 0xc0189436 + FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED = 0x1 FSCRYPT_KEY_DESCRIPTOR_SIZE = 0x8 FSCRYPT_KEY_DESC_PREFIX = "fscrypt:" FSCRYPT_KEY_DESC_PREFIX_SIZE = 0x8 @@ -1574,7 +1590,6 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b - IPV6_FLOW = 0x11 IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 @@ -1625,7 +1640,6 @@ const ( IPV6_TRANSPARENT = 0x4b IPV6_UNICAST_HOPS = 0x10 IPV6_UNICAST_IF = 0x4c - IPV6_USER_FLOW = 0xe IPV6_V6ONLY = 0x1a IPV6_VERSION = 0x60 IPV6_VERSION_MASK = 0xf0 @@ -1687,7 +1701,6 @@ const ( IP_TTL = 0x2 IP_UNBLOCK_SOURCE = 0x25 IP_UNICAST_IF = 0x32 - IP_USER_FLOW = 0xd IP_XFRM_POLICY = 0x11 ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 @@ -1809,7 +1822,11 @@ const ( LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2 LANDLOCK_ACCESS_NET_BIND_TCP = 0x1 LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2 + LANDLOCK_CREATE_RULESET_ERRATA = 0x2 LANDLOCK_CREATE_RULESET_VERSION = 0x1 + LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON = 0x2 + LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF = 0x1 + LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF = 0x4 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = 0x1 LANDLOCK_SCOPE_SIGNAL = 0x2 LINUX_REBOOT_CMD_CAD_OFF = 0x0 @@ -2485,6 +2502,10 @@ const ( PR_FP_EXC_UND = 0x40000 PR_FP_MODE_FR = 0x1 PR_FP_MODE_FRE = 0x2 + PR_FUTEX_HASH = 0x4e + PR_FUTEX_HASH_GET_IMMUTABLE = 0x3 + PR_FUTEX_HASH_GET_SLOTS = 0x2 + PR_FUTEX_HASH_SET_SLOTS = 0x1 PR_GET_AUXV = 0x41555856 PR_GET_CHILD_SUBREAPER = 0x25 PR_GET_DUMPABLE = 0x3 @@ -2644,6 +2665,10 @@ const ( PR_TAGGED_ADDR_ENABLE = 0x1 PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 + PR_TIMER_CREATE_RESTORE_IDS = 0x4d + PR_TIMER_CREATE_RESTORE_IDS_GET = 0x2 + PR_TIMER_CREATE_RESTORE_IDS_OFF = 0x0 + PR_TIMER_CREATE_RESTORE_IDS_ON = 0x1 PR_TIMING_STATISTICAL = 0x0 PR_TIMING_TIMESTAMP = 0x1 PR_TSC_ENABLE = 0x1 @@ -2724,6 +2749,7 @@ const ( PTRACE_SETREGSET = 0x4205 PTRACE_SETSIGINFO = 0x4203 PTRACE_SETSIGMASK = 0x420b + PTRACE_SET_SYSCALL_INFO = 0x4212 PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG = 0x4210 PTRACE_SINGLESTEP = 0x9 PTRACE_SYSCALL = 0x18 @@ -2787,7 +2813,7 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1e + RTA_MAX = 0x1f RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 @@ -2864,10 +2890,12 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELANYCAST = 0x3d RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELLINKPROP = 0x6d RTM_DELMDB = 0x55 + RTM_DELMULTICAST = 0x39 RTM_DELNEIGH = 0x1d RTM_DELNETCONF = 0x51 RTM_DELNEXTHOP = 0x69 @@ -2917,11 +2945,13 @@ const ( RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 + RTM_NEWANYCAST = 0x3c RTM_NEWCACHEREPORT = 0x60 RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWLINKPROP = 0x6c RTM_NEWMDB = 0x54 + RTM_NEWMULTICAST = 0x38 RTM_NEWNDUSEROPT = 0x44 RTM_NEWNEIGH = 0x1c RTM_NEWNEIGHTBL = 0x40 @@ -2970,6 +3000,7 @@ const ( RTPROT_NTK = 0xf RTPROT_OPENR = 0x63 RTPROT_OSPF = 0xbc + RTPROT_OVN = 0x54 RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 RTPROT_RIP = 0xbd @@ -2987,11 +3018,12 @@ const ( RUSAGE_THREAD = 0x1 RWF_APPEND = 0x10 RWF_ATOMIC = 0x40 + RWF_DONTCACHE = 0x80 RWF_DSYNC = 0x2 RWF_HIPRI = 0x1 RWF_NOAPPEND = 0x20 RWF_NOWAIT = 0x8 - RWF_SUPPORTED = 0x7f + RWF_SUPPORTED = 0xff RWF_SYNC = 0x4 RWF_WRITE_LIFE_NOT_SET = 0x0 SCHED_BATCH = 0x3 @@ -3271,6 +3303,7 @@ const ( STATX_BTIME = 0x800 STATX_CTIME = 0x80 STATX_DIOALIGN = 0x2000 + STATX_DIO_READ_ALIGN = 0x20000 STATX_GID = 0x10 STATX_INO = 0x100 STATX_MNT_ID = 0x1000 @@ -3322,7 +3355,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0xe + TASKSTATS_VERSION = 0x10 TCIFLUSH = 0x0 TCIOFF = 0x2 TCIOFLUSH = 0x2 @@ -3392,8 +3425,6 @@ const ( TCP_TX_DELAY = 0x25 TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 - TCP_V4_FLOW = 0x1 - TCP_V6_FLOW = 0x5 TCP_WINDOW_CLAMP = 0xa TCP_ZEROCOPY_RECEIVE = 0x23 TFD_TIMER_ABSTIME = 0x1 @@ -3503,6 +3534,7 @@ const ( TP_STATUS_WRONG_FORMAT = 0x4 TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 + UBI_IOCECNFO = 0xc01c6f06 UDF_SUPER_MAGIC = 0x15013346 UDP_CORK = 0x1 UDP_ENCAP = 0x64 @@ -3515,8 +3547,6 @@ const ( UDP_NO_CHECK6_RX = 0x66 UDP_NO_CHECK6_TX = 0x65 UDP_SEGMENT = 0x67 - UDP_V4_FLOW = 0x2 - UDP_V6_FLOW = 0x6 UMOUNT_NOFOLLOW = 0x8 USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff @@ -3559,7 +3589,7 @@ const ( WDIOS_TEMPPANIC = 0x4 WDIOS_UNKNOWN = -0x1 WEXITED = 0x4 - WGALLOWEDIP_A_MAX = 0x3 + WGALLOWEDIP_A_MAX = 0x4 WGDEVICE_A_MAX = 0x8 WGPEER_A_MAX = 0xa WG_CMD_MAX = 0x1 @@ -3673,6 +3703,7 @@ const ( XDP_SHARED_UMEM = 0x1 XDP_STATISTICS = 0x7 XDP_TXMD_FLAGS_CHECKSUM = 0x2 + XDP_TXMD_FLAGS_LAUNCH_TIME = 0x4 XDP_TXMD_FLAGS_TIMESTAMP = 0x1 XDP_TX_METADATA = 0x2 XDP_TX_RING = 0x3 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 75207613..1c37f9fb 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0xfd12 ECCGETLAYOUT = 0x81484d11 ECCGETSTATS = 0x80104d12 ECHOCTL = 0x200 @@ -360,6 +361,7 @@ const ( SO_OOBINLINE = 0xa SO_PASSCRED = 0x10 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x11 @@ -372,6 +374,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x12 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index c68acda5..6f54d34a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0xfd12 ECCGETLAYOUT = 0x81484d11 ECCGETSTATS = 0x80104d12 ECHOCTL = 0x200 @@ -361,6 +362,7 @@ const ( SO_OOBINLINE = 0xa SO_PASSCRED = 0x10 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x11 @@ -373,6 +375,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x12 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index a8c607ab..783ec5c1 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0xfd12 ECCGETLAYOUT = 0x81484d11 ECCGETSTATS = 0x80104d12 ECHOCTL = 0x200 @@ -366,6 +367,7 @@ const ( SO_OOBINLINE = 0xa SO_PASSCRED = 0x10 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x11 @@ -378,6 +380,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x12 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index 18563dd8..ca83d3ba 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0xfd12 ECCGETLAYOUT = 0x81484d11 ECCGETSTATS = 0x80104d12 ECHOCTL = 0x200 @@ -359,6 +360,7 @@ const ( SO_OOBINLINE = 0xa SO_PASSCRED = 0x10 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x11 @@ -371,6 +373,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x12 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go index 22912cda..607e611c 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0xfd12 ECCGETLAYOUT = 0x81484d11 ECCGETSTATS = 0x80104d12 ECHOCTL = 0x200 @@ -353,6 +354,7 @@ const ( SO_OOBINLINE = 0xa SO_PASSCRED = 0x10 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x11 @@ -365,6 +367,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x12 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index 29344eb3..b9cb5bd3 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0x2000fd12 ECCGETLAYOUT = 0x41484d11 ECCGETSTATS = 0x40104d12 ECHOCTL = 0x200 @@ -359,6 +360,7 @@ const ( SO_OOBINLINE = 0x100 SO_PASSCRED = 0x11 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x12 @@ -371,6 +373,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x1004 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 20d51fb9..65b078a6 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0x2000fd12 ECCGETLAYOUT = 0x41484d11 ECCGETSTATS = 0x40104d12 ECHOCTL = 0x200 @@ -359,6 +360,7 @@ const ( SO_OOBINLINE = 0x100 SO_PASSCRED = 0x11 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x12 @@ -371,6 +373,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x1004 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index 321b6090..5298a303 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0x2000fd12 ECCGETLAYOUT = 0x41484d11 ECCGETSTATS = 0x40104d12 ECHOCTL = 0x200 @@ -359,6 +360,7 @@ const ( SO_OOBINLINE = 0x100 SO_PASSCRED = 0x11 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x12 @@ -371,6 +373,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x1004 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index 9bacdf1e..7bc557c8 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0x2000fd12 ECCGETLAYOUT = 0x41484d11 ECCGETSTATS = 0x40104d12 ECHOCTL = 0x200 @@ -359,6 +360,7 @@ const ( SO_OOBINLINE = 0x100 SO_PASSCRED = 0x11 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x12 @@ -371,6 +373,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x1004 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index c2242726..152399bb 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -68,6 +68,7 @@ const ( CS8 = 0x300 CSIZE = 0x300 CSTOPB = 0x400 + DM_MPATH_PROBE_PATHS = 0x2000fd12 ECCGETLAYOUT = 0x41484d11 ECCGETSTATS = 0x40104d12 ECHOCTL = 0x40 @@ -414,6 +415,7 @@ const ( SO_OOBINLINE = 0xa SO_PASSCRED = 0x14 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x15 @@ -426,6 +428,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x10 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x12 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x12 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 6270c8ee..1a1ce240 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -68,6 +68,7 @@ const ( CS8 = 0x300 CSIZE = 0x300 CSTOPB = 0x400 + DM_MPATH_PROBE_PATHS = 0x2000fd12 ECCGETLAYOUT = 0x41484d11 ECCGETSTATS = 0x40104d12 ECHOCTL = 0x40 @@ -418,6 +419,7 @@ const ( SO_OOBINLINE = 0xa SO_PASSCRED = 0x14 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x15 @@ -430,6 +432,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x10 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x12 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x12 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index 9966c194..4231a1fb 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -68,6 +68,7 @@ const ( CS8 = 0x300 CSIZE = 0x300 CSTOPB = 0x400 + DM_MPATH_PROBE_PATHS = 0x2000fd12 ECCGETLAYOUT = 0x41484d11 ECCGETSTATS = 0x40104d12 ECHOCTL = 0x40 @@ -418,6 +419,7 @@ const ( SO_OOBINLINE = 0xa SO_PASSCRED = 0x14 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x15 @@ -430,6 +432,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x10 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x12 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x12 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index 848e5fcc..21c0e952 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0xfd12 ECCGETLAYOUT = 0x81484d11 ECCGETSTATS = 0x80104d12 ECHOCTL = 0x200 @@ -350,6 +351,7 @@ const ( SO_OOBINLINE = 0xa SO_PASSCRED = 0x10 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x11 @@ -362,6 +364,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x12 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index 669b2adb..f00d1cd7 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -68,6 +68,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0xfd12 ECCGETLAYOUT = 0x81484d11 ECCGETSTATS = 0x80104d12 ECHOCTL = 0x200 @@ -422,6 +423,7 @@ const ( SO_OOBINLINE = 0xa SO_PASSCRED = 0x10 SO_PASSPIDFD = 0x4c + SO_PASSRIGHTS = 0x53 SO_PASSSEC = 0x22 SO_PEEK_OFF = 0x2a SO_PEERCRED = 0x11 @@ -434,6 +436,7 @@ const ( SO_RCVBUFFORCE = 0x21 SO_RCVLOWAT = 0x12 SO_RCVMARK = 0x4b + SO_RCVPRIORITY = 0x52 SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 4834e575..bc8d539e 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -71,6 +71,7 @@ const ( CS8 = 0x30 CSIZE = 0x30 CSTOPB = 0x40 + DM_MPATH_PROBE_PATHS = 0x2000fd12 ECCGETLAYOUT = 0x41484d11 ECCGETSTATS = 0x40104d12 ECHOCTL = 0x200 @@ -461,6 +462,7 @@ const ( SO_OOBINLINE = 0x100 SO_PASSCRED = 0x2 SO_PASSPIDFD = 0x55 + SO_PASSRIGHTS = 0x5c SO_PASSSEC = 0x1f SO_PEEK_OFF = 0x26 SO_PEERCRED = 0x40 @@ -473,6 +475,7 @@ const ( SO_RCVBUFFORCE = 0x100b SO_RCVLOWAT = 0x800 SO_RCVMARK = 0x54 + SO_RCVPRIORITY = 0x5b SO_RCVTIMEO = 0x2000 SO_RCVTIMEO_NEW = 0x44 SO_RCVTIMEO_OLD = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go index 24b346e1..813c05b6 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go @@ -2512,6 +2512,90 @@ var libc_munmap_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func readv(fd int, iovecs []Iovec) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall(libc_readv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_readv_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_readv readv "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall6(libc_preadv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_preadv_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_preadv preadv "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writev(fd int, iovecs []Iovec) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall(libc_writev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_writev_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_writev writev "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall6(libc_pwritev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_pwritev_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pwritev pwritev "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstat(fd int, stat *Stat_t) (err error) { _, _, e1 := syscall_syscall(libc_fstat64_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s index ebd21310..fda32858 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -738,6 +738,26 @@ TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8 DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB) +TEXT libc_readv_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_readv(SB) +GLOBL ·libc_readv_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readv_trampoline_addr(SB)/8, $libc_readv_trampoline<>(SB) + +TEXT libc_preadv_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_preadv(SB) +GLOBL ·libc_preadv_trampoline_addr(SB), RODATA, $8 +DATA ·libc_preadv_trampoline_addr(SB)/8, $libc_preadv_trampoline<>(SB) + +TEXT libc_writev_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_writev(SB) +GLOBL ·libc_writev_trampoline_addr(SB), RODATA, $8 +DATA ·libc_writev_trampoline_addr(SB)/8, $libc_writev_trampoline<>(SB) + +TEXT libc_pwritev_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pwritev(SB) +GLOBL ·libc_pwritev_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pwritev_trampoline_addr(SB)/8, $libc_pwritev_trampoline<>(SB) + TEXT libc_fstat64_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fstat64(SB) GLOBL ·libc_fstat64_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go index 824b9c2d..e6f58f3c 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go @@ -2512,6 +2512,90 @@ var libc_munmap_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func readv(fd int, iovecs []Iovec) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall(libc_readv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_readv_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_readv readv "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall6(libc_preadv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_preadv_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_preadv preadv "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writev(fd int, iovecs []Iovec) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall(libc_writev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_writev_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_writev writev "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall6(libc_pwritev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_pwritev_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pwritev pwritev "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstat(fd int, stat *Stat_t) (err error) { _, _, e1 := syscall_syscall(libc_fstat_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s index 4f178a22..7f8998b9 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -738,6 +738,26 @@ TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8 DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB) +TEXT libc_readv_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_readv(SB) +GLOBL ·libc_readv_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readv_trampoline_addr(SB)/8, $libc_readv_trampoline<>(SB) + +TEXT libc_preadv_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_preadv(SB) +GLOBL ·libc_preadv_trampoline_addr(SB), RODATA, $8 +DATA ·libc_preadv_trampoline_addr(SB)/8, $libc_preadv_trampoline<>(SB) + +TEXT libc_writev_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_writev(SB) +GLOBL ·libc_writev_trampoline_addr(SB), RODATA, $8 +DATA ·libc_writev_trampoline_addr(SB)/8, $libc_writev_trampoline<>(SB) + +TEXT libc_pwritev_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pwritev(SB) +GLOBL ·libc_pwritev_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pwritev_trampoline_addr(SB)/8, $libc_pwritev_trampoline<>(SB) + TEXT libc_fstat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fstat(SB) GLOBL ·libc_fstat_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go index c6545413..b4609c20 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go @@ -72,7 +72,7 @@ import ( //go:cgo_import_dynamic libc_kill kill "libc.so" //go:cgo_import_dynamic libc_lchown lchown "libc.so" //go:cgo_import_dynamic libc_link link "libc.so" -//go:cgo_import_dynamic libc___xnet_llisten __xnet_llisten "libsocket.so" +//go:cgo_import_dynamic libc___xnet_listen __xnet_listen "libsocket.so" //go:cgo_import_dynamic libc_lstat lstat "libc.so" //go:cgo_import_dynamic libc_madvise madvise "libc.so" //go:cgo_import_dynamic libc_mkdir mkdir "libc.so" @@ -221,7 +221,7 @@ import ( //go:linkname procKill libc_kill //go:linkname procLchown libc_lchown //go:linkname procLink libc_link -//go:linkname proc__xnet_llisten libc___xnet_llisten +//go:linkname proc__xnet_listen libc___xnet_listen //go:linkname procLstat libc_lstat //go:linkname procMadvise libc_madvise //go:linkname procMkdir libc_mkdir @@ -371,7 +371,7 @@ var ( procKill, procLchown, procLink, - proc__xnet_llisten, + proc__xnet_listen, procLstat, procMadvise, procMkdir, @@ -1178,7 +1178,7 @@ func Link(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Listen(s int, backlog int) (err error) { - _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_llisten)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0) + _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go index c79aaff3..aca56ee4 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go @@ -462,4 +462,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index 5eb45069..2ea1ef58 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -385,4 +385,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go index 05e50297..d22c8af3 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go @@ -426,4 +426,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index 38c53ec5..5ee264ae 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -329,4 +329,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go index 31d2e71a..f9f03ebf 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go @@ -325,4 +325,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go index f4184a33..87c2118e 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -446,4 +446,5 @@ const ( SYS_GETXATTRAT = 4464 SYS_LISTXATTRAT = 4465 SYS_REMOVEXATTRAT = 4466 + SYS_OPEN_TREE_ATTR = 4467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go index 05b99622..391ad102 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go @@ -376,4 +376,5 @@ const ( SYS_GETXATTRAT = 5464 SYS_LISTXATTRAT = 5465 SYS_REMOVEXATTRAT = 5466 + SYS_OPEN_TREE_ATTR = 5467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go index 43a256e9..56561577 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go @@ -376,4 +376,5 @@ const ( SYS_GETXATTRAT = 5464 SYS_LISTXATTRAT = 5465 SYS_REMOVEXATTRAT = 5466 + SYS_OPEN_TREE_ATTR = 5467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go index eea5ddfc..0482b52e 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -446,4 +446,5 @@ const ( SYS_GETXATTRAT = 4464 SYS_LISTXATTRAT = 4465 SYS_REMOVEXATTRAT = 4466 + SYS_OPEN_TREE_ATTR = 4467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go index 0d777bfb..71806f08 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go @@ -453,4 +453,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go index b4463650..e35a7105 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go @@ -425,4 +425,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go index 0c7d21c1..2aea4767 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go @@ -425,4 +425,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index 84053916..6c9bb4e5 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -330,4 +330,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index fcf1b790..680bc991 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -391,4 +391,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index 52d15b5f..620f2710 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -404,4 +404,5 @@ const ( SYS_GETXATTRAT = 464 SYS_LISTXATTRAT = 465 SYS_REMOVEXATTRAT = 466 + SYS_OPEN_TREE_ATTR = 467 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index a46abe64..944e75a1 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -114,8 +114,10 @@ type Statx_t struct { Atomic_write_unit_min uint32 Atomic_write_unit_max uint32 Atomic_write_segments_max uint32 + Dio_read_offset_align uint32 + Atomic_write_unit_max_opt uint32 _ [1]uint32 - _ [9]uint64 + _ [8]uint64 } type Fsid struct { @@ -199,7 +201,8 @@ type FscryptAddKeyArg struct { Key_spec FscryptKeySpecifier Raw_size uint32 Key_id uint32 - _ [8]uint32 + Flags uint32 + _ [7]uint32 } type FscryptRemoveKeyArg struct { @@ -629,6 +632,8 @@ const ( IFA_FLAGS = 0x8 IFA_RT_PRIORITY = 0x9 IFA_TARGET_NETNSID = 0xa + IFAL_LABEL = 0x2 + IFAL_ADDRESS = 0x1 RT_SCOPE_UNIVERSE = 0x0 RT_SCOPE_SITE = 0xc8 RT_SCOPE_LINK = 0xfd @@ -686,6 +691,7 @@ const ( SizeofRtAttr = 0x4 SizeofIfInfomsg = 0x10 SizeofIfAddrmsg = 0x8 + SizeofIfAddrlblmsg = 0xc SizeofIfaCacheinfo = 0x10 SizeofRtMsg = 0xc SizeofRtNexthop = 0x8 @@ -737,6 +743,15 @@ type IfAddrmsg struct { Index uint32 } +type IfAddrlblmsg struct { + Family uint8 + _ uint8 + Prefixlen uint8 + Flags uint8 + Index uint32 + Seq uint32 +} + type IfaCacheinfo struct { Prefered uint32 Valid uint32 @@ -2226,8 +2241,11 @@ const ( NFT_PAYLOAD_LL_HEADER = 0x0 NFT_PAYLOAD_NETWORK_HEADER = 0x1 NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_INNER_HEADER = 0x3 + NFT_PAYLOAD_TUN_HEADER = 0x4 NFT_PAYLOAD_CSUM_NONE = 0x0 NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_CSUM_SCTP = 0x2 NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 NFTA_PAYLOAD_UNSPEC = 0x0 NFTA_PAYLOAD_DREG = 0x1 @@ -2314,6 +2332,11 @@ const ( NFT_CT_AVGPKT = 0x10 NFT_CT_ZONE = 0x11 NFT_CT_EVENTMASK = 0x12 + NFT_CT_SRC_IP = 0x13 + NFT_CT_DST_IP = 0x14 + NFT_CT_SRC_IP6 = 0x15 + NFT_CT_DST_IP6 = 0x16 + NFT_CT_ID = 0x17 NFTA_CT_UNSPEC = 0x0 NFTA_CT_DREG = 0x1 NFTA_CT_KEY = 0x2 @@ -2594,8 +2617,8 @@ const ( SOF_TIMESTAMPING_BIND_PHC = 0x8000 SOF_TIMESTAMPING_OPT_ID_TCP = 0x10000 - SOF_TIMESTAMPING_LAST = 0x20000 - SOF_TIMESTAMPING_MASK = 0x3ffff + SOF_TIMESTAMPING_LAST = 0x40000 + SOF_TIMESTAMPING_MASK = 0x7ffff SCM_TSTAMP_SND = 0x0 SCM_TSTAMP_SCHED = 0x1 @@ -3041,6 +3064,23 @@ const ( ) const ( + TCA_UNSPEC = 0x0 + TCA_KIND = 0x1 + TCA_OPTIONS = 0x2 + TCA_STATS = 0x3 + TCA_XSTATS = 0x4 + TCA_RATE = 0x5 + TCA_FCNT = 0x6 + TCA_STATS2 = 0x7 + TCA_STAB = 0x8 + TCA_PAD = 0x9 + TCA_DUMP_INVISIBLE = 0xa + TCA_CHAIN = 0xb + TCA_HW_OFFLOAD = 0xc + TCA_INGRESS_BLOCK = 0xd + TCA_EGRESS_BLOCK = 0xe + TCA_DUMP_FLAGS = 0xf + TCA_EXT_WARN_MSG = 0x10 RTNLGRP_NONE = 0x0 RTNLGRP_LINK = 0x1 RTNLGRP_NOTIFY = 0x2 @@ -3075,6 +3115,18 @@ const ( RTNLGRP_IPV6_MROUTE_R = 0x1f RTNLGRP_NEXTHOP = 0x20 RTNLGRP_BRVLAN = 0x21 + RTNLGRP_MCTP_IFADDR = 0x22 + RTNLGRP_TUNNEL = 0x23 + RTNLGRP_STATS = 0x24 + RTNLGRP_IPV4_MCADDR = 0x25 + RTNLGRP_IPV6_MCADDR = 0x26 + RTNLGRP_IPV6_ACADDR = 0x27 + TCA_ROOT_UNSPEC = 0x0 + TCA_ROOT_TAB = 0x1 + TCA_ROOT_FLAGS = 0x2 + TCA_ROOT_COUNT = 0x3 + TCA_ROOT_TIME_DELTA = 0x4 + TCA_ROOT_EXT_WARN_MSG = 0x5 ) type CapUserHeader struct { @@ -3802,7 +3854,16 @@ const ( ETHTOOL_MSG_PSE_GET = 0x24 ETHTOOL_MSG_PSE_SET = 0x25 ETHTOOL_MSG_RSS_GET = 0x26 - ETHTOOL_MSG_USER_MAX = 0x2d + ETHTOOL_MSG_PLCA_GET_CFG = 0x27 + ETHTOOL_MSG_PLCA_SET_CFG = 0x28 + ETHTOOL_MSG_PLCA_GET_STATUS = 0x29 + ETHTOOL_MSG_MM_GET = 0x2a + ETHTOOL_MSG_MM_SET = 0x2b + ETHTOOL_MSG_MODULE_FW_FLASH_ACT = 0x2c + ETHTOOL_MSG_PHY_GET = 0x2d + ETHTOOL_MSG_TSCONFIG_GET = 0x2e + ETHTOOL_MSG_TSCONFIG_SET = 0x2f + ETHTOOL_MSG_USER_MAX = 0x2f ETHTOOL_MSG_KERNEL_NONE = 0x0 ETHTOOL_MSG_STRSET_GET_REPLY = 0x1 ETHTOOL_MSG_LINKINFO_GET_REPLY = 0x2 @@ -3842,7 +3903,17 @@ const ( ETHTOOL_MSG_MODULE_NTF = 0x24 ETHTOOL_MSG_PSE_GET_REPLY = 0x25 ETHTOOL_MSG_RSS_GET_REPLY = 0x26 - ETHTOOL_MSG_KERNEL_MAX = 0x2e + ETHTOOL_MSG_PLCA_GET_CFG_REPLY = 0x27 + ETHTOOL_MSG_PLCA_GET_STATUS_REPLY = 0x28 + ETHTOOL_MSG_PLCA_NTF = 0x29 + ETHTOOL_MSG_MM_GET_REPLY = 0x2a + ETHTOOL_MSG_MM_NTF = 0x2b + ETHTOOL_MSG_MODULE_FW_FLASH_NTF = 0x2c + ETHTOOL_MSG_PHY_GET_REPLY = 0x2d + ETHTOOL_MSG_PHY_NTF = 0x2e + ETHTOOL_MSG_TSCONFIG_GET_REPLY = 0x2f + ETHTOOL_MSG_TSCONFIG_SET_REPLY = 0x30 + ETHTOOL_MSG_KERNEL_MAX = 0x30 ETHTOOL_FLAG_COMPACT_BITSETS = 0x1 ETHTOOL_FLAG_OMIT_REPLY = 0x2 ETHTOOL_FLAG_STATS = 0x4 @@ -3949,7 +4020,12 @@ const ( ETHTOOL_A_RINGS_TCP_DATA_SPLIT = 0xb ETHTOOL_A_RINGS_CQE_SIZE = 0xc ETHTOOL_A_RINGS_TX_PUSH = 0xd - ETHTOOL_A_RINGS_MAX = 0x10 + ETHTOOL_A_RINGS_RX_PUSH = 0xe + ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN = 0xf + ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX = 0x10 + ETHTOOL_A_RINGS_HDS_THRESH = 0x11 + ETHTOOL_A_RINGS_HDS_THRESH_MAX = 0x12 + ETHTOOL_A_RINGS_MAX = 0x12 ETHTOOL_A_CHANNELS_UNSPEC = 0x0 ETHTOOL_A_CHANNELS_HEADER = 0x1 ETHTOOL_A_CHANNELS_RX_MAX = 0x2 @@ -4015,7 +4091,9 @@ const ( ETHTOOL_A_TSINFO_TX_TYPES = 0x3 ETHTOOL_A_TSINFO_RX_FILTERS = 0x4 ETHTOOL_A_TSINFO_PHC_INDEX = 0x5 - ETHTOOL_A_TSINFO_MAX = 0x6 + ETHTOOL_A_TSINFO_STATS = 0x6 + ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER = 0x7 + ETHTOOL_A_TSINFO_MAX = 0x9 ETHTOOL_A_CABLE_TEST_UNSPEC = 0x0 ETHTOOL_A_CABLE_TEST_HEADER = 0x1 ETHTOOL_A_CABLE_TEST_MAX = 0x1 @@ -4101,6 +4179,19 @@ const ( ETHTOOL_A_TUNNEL_INFO_MAX = 0x2 ) +const ( + TCP_V4_FLOW = 0x1 + UDP_V4_FLOW = 0x2 + TCP_V6_FLOW = 0x5 + UDP_V6_FLOW = 0x6 + ESP_V4_FLOW = 0xa + ESP_V6_FLOW = 0xc + IP_USER_FLOW = 0xd + IPV6_USER_FLOW = 0xe + IPV6_FLOW = 0x11 + ETHER_FLOW = 0x12 +) + const SPEED_UNKNOWN = -0x1 type EthtoolDrvinfo struct { @@ -4613,6 +4704,7 @@ const ( NL80211_ATTR_AKM_SUITES = 0x4c NL80211_ATTR_AP_ISOLATE = 0x60 NL80211_ATTR_AP_SETTINGS_FLAGS = 0x135 + NL80211_ATTR_ASSOC_SPP_AMSDU = 0x14a NL80211_ATTR_AUTH_DATA = 0x9c NL80211_ATTR_AUTH_TYPE = 0x35 NL80211_ATTR_BANDS = 0xef @@ -4623,6 +4715,7 @@ const ( NL80211_ATTR_BSS_BASIC_RATES = 0x24 NL80211_ATTR_BSS = 0x2f NL80211_ATTR_BSS_CTS_PROT = 0x1c + NL80211_ATTR_BSS_DUMP_INCLUDE_USE_DATA = 0x147 NL80211_ATTR_BSS_HT_OPMODE = 0x6d NL80211_ATTR_BSSID = 0xf5 NL80211_ATTR_BSS_SELECT = 0xe3 @@ -4682,6 +4775,7 @@ const ( NL80211_ATTR_DTIM_PERIOD = 0xd NL80211_ATTR_DURATION = 0x57 NL80211_ATTR_EHT_CAPABILITY = 0x136 + NL80211_ATTR_EMA_RNR_ELEMS = 0x145 NL80211_ATTR_EML_CAPABILITY = 0x13d NL80211_ATTR_EXT_CAPA = 0xa9 NL80211_ATTR_EXT_CAPA_MASK = 0xaa @@ -4717,6 +4811,7 @@ const ( NL80211_ATTR_HIDDEN_SSID = 0x7e NL80211_ATTR_HT_CAPABILITY = 0x1f NL80211_ATTR_HT_CAPABILITY_MASK = 0x94 + NL80211_ATTR_HW_TIMESTAMP_ENABLED = 0x144 NL80211_ATTR_IE_ASSOC_RESP = 0x80 NL80211_ATTR_IE = 0x2a NL80211_ATTR_IE_PROBE_RESP = 0x7f @@ -4747,9 +4842,10 @@ const ( NL80211_ATTR_MAC_HINT = 0xc8 NL80211_ATTR_MAC_MASK = 0xd7 NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca - NL80211_ATTR_MAX = 0x14d + NL80211_ATTR_MAX = 0x151 NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4 NL80211_ATTR_MAX_CSA_COUNTERS = 0xce + NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS = 0x143 NL80211_ATTR_MAX_MATCH_SETS = 0x85 NL80211_ATTR_MAX_NUM_AKM_SUITES = 0x13c NL80211_ATTR_MAX_NUM_PMKIDS = 0x56 @@ -4774,9 +4870,12 @@ const ( NL80211_ATTR_MGMT_SUBTYPE = 0x29 NL80211_ATTR_MLD_ADDR = 0x13a NL80211_ATTR_MLD_CAPA_AND_OPS = 0x13e + NL80211_ATTR_MLO_LINK_DISABLED = 0x146 NL80211_ATTR_MLO_LINK_ID = 0x139 NL80211_ATTR_MLO_LINKS = 0x138 NL80211_ATTR_MLO_SUPPORT = 0x13b + NL80211_ATTR_MLO_TTLM_DLINK = 0x148 + NL80211_ATTR_MLO_TTLM_ULINK = 0x149 NL80211_ATTR_MNTR_FLAGS = 0x17 NL80211_ATTR_MPATH_INFO = 0x1b NL80211_ATTR_MPATH_NEXT_HOP = 0x1a @@ -4809,12 +4908,14 @@ const ( NL80211_ATTR_PORT_AUTHORIZED = 0x103 NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN = 0x5 NL80211_ATTR_POWER_RULE_MAX_EIRP = 0x6 + NL80211_ATTR_POWER_RULE_PSD = 0x8 NL80211_ATTR_PREV_BSSID = 0x4f NL80211_ATTR_PRIVACY = 0x46 NL80211_ATTR_PROBE_RESP = 0x91 NL80211_ATTR_PROBE_RESP_OFFLOAD = 0x90 NL80211_ATTR_PROTOCOL_FEATURES = 0xad NL80211_ATTR_PS_STATE = 0x5d + NL80211_ATTR_PUNCT_BITMAP = 0x142 NL80211_ATTR_QOS_MAP = 0xc7 NL80211_ATTR_RADAR_BACKGROUND = 0x134 NL80211_ATTR_RADAR_EVENT = 0xa8 @@ -4943,7 +5044,9 @@ const ( NL80211_ATTR_WIPHY_FREQ = 0x26 NL80211_ATTR_WIPHY_FREQ_HINT = 0xc9 NL80211_ATTR_WIPHY_FREQ_OFFSET = 0x122 + NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS = 0x14c NL80211_ATTR_WIPHY_NAME = 0x2 + NL80211_ATTR_WIPHY_RADIOS = 0x14b NL80211_ATTR_WIPHY_RETRY_LONG = 0x3e NL80211_ATTR_WIPHY_RETRY_SHORT = 0x3d NL80211_ATTR_WIPHY_RTS_THRESHOLD = 0x40 @@ -4978,6 +5081,8 @@ const ( NL80211_BAND_ATTR_IFTYPE_DATA = 0x9 NL80211_BAND_ATTR_MAX = 0xd NL80211_BAND_ATTR_RATES = 0x2 + NL80211_BAND_ATTR_S1G_CAPA = 0xd + NL80211_BAND_ATTR_S1G_MCS_NSS_SET = 0xc NL80211_BAND_ATTR_VHT_CAPA = 0x8 NL80211_BAND_ATTR_VHT_MCS_SET = 0x7 NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC = 0x8 @@ -5001,6 +5106,10 @@ const ( NL80211_BSS_BEACON_INTERVAL = 0x4 NL80211_BSS_BEACON_TSF = 0xd NL80211_BSS_BSSID = 0x1 + NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH = 0x2 + NL80211_BSS_CANNOT_USE_NSTR_NONPRIMARY = 0x1 + NL80211_BSS_CANNOT_USE_REASONS = 0x18 + NL80211_BSS_CANNOT_USE_UHB_PWR_MISMATCH = 0x2 NL80211_BSS_CAPABILITY = 0x5 NL80211_BSS_CHAIN_SIGNAL = 0x13 NL80211_BSS_CHAN_WIDTH_10 = 0x1 @@ -5032,6 +5141,9 @@ const ( NL80211_BSS_STATUS = 0x9 NL80211_BSS_STATUS_IBSS_JOINED = 0x2 NL80211_BSS_TSF = 0x3 + NL80211_BSS_USE_FOR = 0x17 + NL80211_BSS_USE_FOR_MLD_LINK = 0x2 + NL80211_BSS_USE_FOR_NORMAL = 0x1 NL80211_CHAN_HT20 = 0x1 NL80211_CHAN_HT40MINUS = 0x2 NL80211_CHAN_HT40PLUS = 0x3 @@ -5117,7 +5229,8 @@ const ( NL80211_CMD_LEAVE_IBSS = 0x2c NL80211_CMD_LEAVE_MESH = 0x45 NL80211_CMD_LEAVE_OCB = 0x6d - NL80211_CMD_MAX = 0x9b + NL80211_CMD_LINKS_REMOVED = 0x9a + NL80211_CMD_MAX = 0x9d NL80211_CMD_MICHAEL_MIC_FAILURE = 0x29 NL80211_CMD_MODIFY_LINK_STA = 0x97 NL80211_CMD_NAN_MATCH = 0x78 @@ -5161,6 +5274,7 @@ const ( NL80211_CMD_SET_COALESCE = 0x65 NL80211_CMD_SET_CQM = 0x3f NL80211_CMD_SET_FILS_AAD = 0x92 + NL80211_CMD_SET_HW_TIMESTAMP = 0x99 NL80211_CMD_SET_INTERFACE = 0x6 NL80211_CMD_SET_KEY = 0xa NL80211_CMD_SET_MAC_ACL = 0x5d @@ -5180,6 +5294,7 @@ const ( NL80211_CMD_SET_SAR_SPECS = 0x8c NL80211_CMD_SET_STATION = 0x12 NL80211_CMD_SET_TID_CONFIG = 0x89 + NL80211_CMD_SET_TID_TO_LINK_MAPPING = 0x9b NL80211_CMD_SET_TX_BITRATE_MASK = 0x39 NL80211_CMD_SET_WDS_PEER = 0x42 NL80211_CMD_SET_WIPHY = 0x2 @@ -5247,6 +5362,7 @@ const ( NL80211_EXT_FEATURE_AIRTIME_FAIRNESS = 0x21 NL80211_EXT_FEATURE_AP_PMKSA_CACHING = 0x22 NL80211_EXT_FEATURE_AQL = 0x28 + NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA = 0x40 NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT = 0x2e NL80211_EXT_FEATURE_BEACON_PROTECTION = 0x29 NL80211_EXT_FEATURE_BEACON_RATE_HE = 0x36 @@ -5262,6 +5378,7 @@ const ( NL80211_EXT_FEATURE_CQM_RSSI_LIST = 0xd NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT = 0x1b NL80211_EXT_FEATURE_DEL_IBSS_STA = 0x2c + NL80211_EXT_FEATURE_DFS_CONCURRENT = 0x43 NL80211_EXT_FEATURE_DFS_OFFLOAD = 0x19 NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER = 0x20 NL80211_EXT_FEATURE_EXT_KEY_ID = 0x24 @@ -5281,9 +5398,12 @@ const ( NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION = 0x14 NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE = 0x13 NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION = 0x31 + NL80211_EXT_FEATURE_OWE_OFFLOAD_AP = 0x42 + NL80211_EXT_FEATURE_OWE_OFFLOAD = 0x41 NL80211_EXT_FEATURE_POWERED_ADDR_CHANGE = 0x3d NL80211_EXT_FEATURE_PROTECTED_TWT = 0x2b NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE = 0x39 + NL80211_EXT_FEATURE_PUNCT = 0x3e NL80211_EXT_FEATURE_RADAR_BACKGROUND = 0x3c NL80211_EXT_FEATURE_RRM = 0x1 NL80211_EXT_FEATURE_SAE_OFFLOAD_AP = 0x33 @@ -5295,8 +5415,10 @@ const ( NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD = 0x23 NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI = 0xc NL80211_EXT_FEATURE_SECURE_LTF = 0x37 + NL80211_EXT_FEATURE_SECURE_NAN = 0x3f NL80211_EXT_FEATURE_SECURE_RTT = 0x38 NL80211_EXT_FEATURE_SET_SCAN_DWELL = 0x5 + NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT = 0x44 NL80211_EXT_FEATURE_STA_TX_PWR = 0x25 NL80211_EXT_FEATURE_TXQS = 0x1c NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP = 0x35 @@ -5343,7 +5465,10 @@ const ( NL80211_FREQUENCY_ATTR_2MHZ = 0x16 NL80211_FREQUENCY_ATTR_4MHZ = 0x17 NL80211_FREQUENCY_ATTR_8MHZ = 0x18 + NL80211_FREQUENCY_ATTR_ALLOW_6GHZ_VLP_AP = 0x21 + NL80211_FREQUENCY_ATTR_CAN_MONITOR = 0x20 NL80211_FREQUENCY_ATTR_DFS_CAC_TIME = 0xd + NL80211_FREQUENCY_ATTR_DFS_CONCURRENT = 0x1d NL80211_FREQUENCY_ATTR_DFS_STATE = 0x7 NL80211_FREQUENCY_ATTR_DFS_TIME = 0x8 NL80211_FREQUENCY_ATTR_DISABLED = 0x2 @@ -5351,12 +5476,14 @@ const ( NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf - NL80211_FREQUENCY_ATTR_MAX = 0x21 + NL80211_FREQUENCY_ATTR_MAX = 0x22 NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6 NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11 NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc NL80211_FREQUENCY_ATTR_NO_20MHZ = 0x10 NL80211_FREQUENCY_ATTR_NO_320MHZ = 0x1a + NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT = 0x1f + NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT = 0x1e NL80211_FREQUENCY_ATTR_NO_80MHZ = 0xb NL80211_FREQUENCY_ATTR_NO_EHT = 0x1b NL80211_FREQUENCY_ATTR_NO_HE = 0x13 @@ -5364,8 +5491,11 @@ const ( NL80211_FREQUENCY_ATTR_NO_HT40_PLUS = 0xa NL80211_FREQUENCY_ATTR_NO_IBSS = 0x3 NL80211_FREQUENCY_ATTR_NO_IR = 0x3 + NL80211_FREQUENCY_ATTR_NO_UHB_AFC_CLIENT = 0x1f + NL80211_FREQUENCY_ATTR_NO_UHB_VLP_CLIENT = 0x1e NL80211_FREQUENCY_ATTR_OFFSET = 0x14 NL80211_FREQUENCY_ATTR_PASSIVE_SCAN = 0x3 + NL80211_FREQUENCY_ATTR_PSD = 0x1c NL80211_FREQUENCY_ATTR_RADAR = 0x5 NL80211_FREQUENCY_ATTR_WMM = 0x12 NL80211_FTM_RESP_ATTR_CIVICLOC = 0x3 @@ -5430,6 +5560,7 @@ const ( NL80211_IFTYPE_STATION = 0x2 NL80211_IFTYPE_UNSPECIFIED = 0x0 NL80211_IFTYPE_WDS = 0x5 + NL80211_KCK_EXT_LEN_32 = 0x20 NL80211_KCK_EXT_LEN = 0x18 NL80211_KCK_LEN = 0x10 NL80211_KEK_EXT_LEN = 0x20 @@ -5458,9 +5589,10 @@ const ( NL80211_MAX_SUPP_HT_RATES = 0x4d NL80211_MAX_SUPP_RATES = 0x20 NL80211_MAX_SUPP_REG_RULES = 0x80 + NL80211_MAX_SUPP_SELECTORS = 0x80 NL80211_MBSSID_CONFIG_ATTR_EMA = 0x5 NL80211_MBSSID_CONFIG_ATTR_INDEX = 0x3 - NL80211_MBSSID_CONFIG_ATTR_MAX = 0x5 + NL80211_MBSSID_CONFIG_ATTR_MAX = 0x6 NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY = 0x2 NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES = 0x1 NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX = 0x4 @@ -5703,11 +5835,16 @@ const ( NL80211_RADAR_PRE_CAC_EXPIRED = 0x4 NL80211_RATE_INFO_10_MHZ_WIDTH = 0xb NL80211_RATE_INFO_160_MHZ_WIDTH = 0xa + NL80211_RATE_INFO_16_MHZ_WIDTH = 0x1d + NL80211_RATE_INFO_1_MHZ_WIDTH = 0x19 + NL80211_RATE_INFO_2_MHZ_WIDTH = 0x1a NL80211_RATE_INFO_320_MHZ_WIDTH = 0x12 NL80211_RATE_INFO_40_MHZ_WIDTH = 0x3 + NL80211_RATE_INFO_4_MHZ_WIDTH = 0x1b NL80211_RATE_INFO_5_MHZ_WIDTH = 0xc NL80211_RATE_INFO_80_MHZ_WIDTH = 0x8 NL80211_RATE_INFO_80P80_MHZ_WIDTH = 0x9 + NL80211_RATE_INFO_8_MHZ_WIDTH = 0x1c NL80211_RATE_INFO_BITRATE32 = 0x5 NL80211_RATE_INFO_BITRATE = 0x1 NL80211_RATE_INFO_EHT_GI_0_8 = 0x0 @@ -5753,6 +5890,8 @@ const ( NL80211_RATE_INFO_HE_RU_ALLOC = 0x11 NL80211_RATE_INFO_MAX = 0x1d NL80211_RATE_INFO_MCS = 0x2 + NL80211_RATE_INFO_S1G_MCS = 0x17 + NL80211_RATE_INFO_S1G_NSS = 0x18 NL80211_RATE_INFO_SHORT_GI = 0x4 NL80211_RATE_INFO_VHT_MCS = 0x6 NL80211_RATE_INFO_VHT_NSS = 0x7 @@ -5770,14 +5909,19 @@ const ( NL80211_REKEY_DATA_KEK = 0x1 NL80211_REKEY_DATA_REPLAY_CTR = 0x3 NL80211_REPLAY_CTR_LEN = 0x8 + NL80211_RRF_ALLOW_6GHZ_VLP_AP = 0x1000000 NL80211_RRF_AUTO_BW = 0x800 NL80211_RRF_DFS = 0x10 + NL80211_RRF_DFS_CONCURRENT = 0x200000 NL80211_RRF_GO_CONCURRENT = 0x1000 NL80211_RRF_IR_CONCURRENT = 0x1000 NL80211_RRF_NO_160MHZ = 0x10000 NL80211_RRF_NO_320MHZ = 0x40000 + NL80211_RRF_NO_6GHZ_AFC_CLIENT = 0x800000 + NL80211_RRF_NO_6GHZ_VLP_CLIENT = 0x400000 NL80211_RRF_NO_80MHZ = 0x8000 NL80211_RRF_NO_CCK = 0x2 + NL80211_RRF_NO_EHT = 0x80000 NL80211_RRF_NO_HE = 0x20000 NL80211_RRF_NO_HT40 = 0x6000 NL80211_RRF_NO_HT40MINUS = 0x2000 @@ -5788,7 +5932,10 @@ const ( NL80211_RRF_NO_IR = 0x80 NL80211_RRF_NO_OFDM = 0x1 NL80211_RRF_NO_OUTDOOR = 0x8 + NL80211_RRF_NO_UHB_AFC_CLIENT = 0x800000 + NL80211_RRF_NO_UHB_VLP_CLIENT = 0x400000 NL80211_RRF_PASSIVE_SCAN = 0x80 + NL80211_RRF_PSD = 0x100000 NL80211_RRF_PTMP_ONLY = 0x40 NL80211_RRF_PTP_ONLY = 0x20 NL80211_RXMGMT_FLAG_ANSWERED = 0x1 @@ -5849,6 +5996,7 @@ const ( NL80211_STA_FLAG_MAX_OLD_API = 0x6 NL80211_STA_FLAG_MFP = 0x4 NL80211_STA_FLAG_SHORT_PREAMBLE = 0x2 + NL80211_STA_FLAG_SPP_AMSDU = 0x8 NL80211_STA_FLAG_TDLS_PEER = 0x6 NL80211_STA_FLAG_WME = 0x3 NL80211_STA_INFO_ACK_SIGNAL_AVG = 0x23 @@ -6007,6 +6155,13 @@ const ( NL80211_VHT_CAPABILITY_LEN = 0xc NL80211_VHT_NSS_MAX = 0x8 NL80211_WIPHY_NAME_MAXLEN = 0x40 + NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE = 0x2 + NL80211_WIPHY_RADIO_ATTR_INDEX = 0x1 + NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION = 0x3 + NL80211_WIPHY_RADIO_ATTR_MAX = 0x4 + NL80211_WIPHY_RADIO_FREQ_ATTR_END = 0x2 + NL80211_WIPHY_RADIO_FREQ_ATTR_MAX = 0x2 + NL80211_WIPHY_RADIO_FREQ_ATTR_START = 0x1 NL80211_WMMR_AIFSN = 0x3 NL80211_WMMR_CW_MAX = 0x2 NL80211_WMMR_CW_MIN = 0x1 @@ -6038,6 +6193,7 @@ const ( NL80211_WOWLAN_TRIG_PKT_PATTERN = 0x4 NL80211_WOWLAN_TRIG_RFKILL_RELEASE = 0x9 NL80211_WOWLAN_TRIG_TCP_CONNECTION = 0xe + NL80211_WOWLAN_TRIG_UNPROTECTED_DEAUTH_DISASSOC = 0x14 NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211 = 0xa NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN = 0xb NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023 = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go index fd402da4..485f2d3a 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go @@ -282,7 +282,7 @@ type Taskstats struct { Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - _ [4]byte + _ [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -338,6 +338,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint32 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go index eb7a5e18..ecbd1ad8 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go @@ -351,6 +351,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint64 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go index d78ac108..02f0463a 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go @@ -91,7 +91,7 @@ type Stat_t struct { Gid uint32 Rdev uint64 _ uint16 - _ [4]byte + _ [6]byte Size int64 Blksize int32 _ [4]byte @@ -273,7 +273,7 @@ type Taskstats struct { Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - _ [4]byte + _ [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -329,6 +329,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint32 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go index cd06d47f..6f4d400d 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go @@ -330,6 +330,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint64 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go index 2f28fe26..cd532cfa 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go @@ -331,6 +331,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint64 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go index 71d6cac2..41336208 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go @@ -278,7 +278,7 @@ type Taskstats struct { Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - _ [4]byte + _ [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -334,6 +334,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint32 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go index 8596d453..eaa37eb7 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go @@ -333,6 +333,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint64 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go index cd60ea18..98ae6a1e 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go @@ -333,6 +333,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint64 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go index b0ae420c..cae19615 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go @@ -278,7 +278,7 @@ type Taskstats struct { Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - _ [4]byte + _ [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -334,6 +334,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint32 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go index 83597287..6ce3b4e0 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go @@ -90,7 +90,7 @@ type Stat_t struct { Gid uint32 Rdev uint64 _ uint16 - _ [4]byte + _ [6]byte Size int64 Blksize int32 _ [4]byte @@ -285,7 +285,7 @@ type Taskstats struct { Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - _ [4]byte + _ [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -341,6 +341,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint32 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go index 69eb6a5c..c7429c6a 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go @@ -340,6 +340,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint64 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go index 5f583cb6..4bf4baf4 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go @@ -340,6 +340,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint64 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go index ad05b51a..e9709d70 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -358,6 +358,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint64 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index cf3ce900..fb44268c 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -353,6 +353,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint64 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go index 590b5673..9c38265c 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go @@ -335,6 +335,22 @@ type Taskstats struct { Wpcopy_delay_total uint64 Irq_count uint64 Irq_delay_total uint64 + Cpu_delay_max uint64 + Cpu_delay_min uint64 + Blkio_delay_max uint64 + Blkio_delay_min uint64 + Swapin_delay_max uint64 + Swapin_delay_min uint64 + Freepages_delay_max uint64 + Freepages_delay_min uint64 + Thrashing_delay_max uint64 + Thrashing_delay_min uint64 + Compact_delay_max uint64 + Compact_delay_min uint64 + Wpcopy_delay_max uint64 + Wpcopy_delay_min uint64 + Irq_delay_max uint64 + Irq_delay_min uint64 } type cpuMask uint64 diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go index b6e1ab76..a8b0364c 100644 --- a/vendor/golang.org/x/sys/windows/security_windows.go +++ b/vendor/golang.org/x/sys/windows/security_windows.go @@ -1303,7 +1303,10 @@ func (selfRelativeSD *SECURITY_DESCRIPTOR) ToAbsolute() (absoluteSD *SECURITY_DE return nil, err } if absoluteSDSize > 0 { - absoluteSD = (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&make([]byte, absoluteSDSize)[0])) + absoluteSD = new(SECURITY_DESCRIPTOR) + if unsafe.Sizeof(*absoluteSD) < uintptr(absoluteSDSize) { + panic("sizeof(SECURITY_DESCRIPTOR) too small") + } } var ( dacl *ACL @@ -1312,19 +1315,55 @@ func (selfRelativeSD *SECURITY_DESCRIPTOR) ToAbsolute() (absoluteSD *SECURITY_DE group *SID ) if daclSize > 0 { - dacl = (*ACL)(unsafe.Pointer(&make([]byte, daclSize)[0])) + dacl = (*ACL)(unsafe.Pointer(unsafe.SliceData(make([]byte, daclSize)))) } if saclSize > 0 { - sacl = (*ACL)(unsafe.Pointer(&make([]byte, saclSize)[0])) + sacl = (*ACL)(unsafe.Pointer(unsafe.SliceData(make([]byte, saclSize)))) } if ownerSize > 0 { - owner = (*SID)(unsafe.Pointer(&make([]byte, ownerSize)[0])) + owner = (*SID)(unsafe.Pointer(unsafe.SliceData(make([]byte, ownerSize)))) } if groupSize > 0 { - group = (*SID)(unsafe.Pointer(&make([]byte, groupSize)[0])) + group = (*SID)(unsafe.Pointer(unsafe.SliceData(make([]byte, groupSize)))) } + // We call into Windows via makeAbsoluteSD, which sets up + // pointers within absoluteSD that point to other chunks of memory + // we pass into makeAbsoluteSD, and that happens outside the view of the GC. + // We therefore take some care here to then verify the pointers are as we expect + // and set them explicitly in view of the GC. See https://go.dev/issue/73199. + // TODO: consider weak pointers once Go 1.24 is appropriate. See suggestion in https://go.dev/cl/663575. err = makeAbsoluteSD(selfRelativeSD, absoluteSD, &absoluteSDSize, dacl, &daclSize, sacl, &saclSize, owner, &ownerSize, group, &groupSize) + if err != nil { + // Don't return absoluteSD, which might be partially initialized. + return nil, err + } + // Before using any fields, verify absoluteSD is in the format we expect according to Windows. + // See https://learn.microsoft.com/en-us/windows/win32/secauthz/absolute-and-self-relative-security-descriptors + absControl, _, err := absoluteSD.Control() + if err != nil { + panic("absoluteSD: " + err.Error()) + } + if absControl&SE_SELF_RELATIVE != 0 { + panic("absoluteSD not in absolute format") + } + if absoluteSD.dacl != dacl { + panic("dacl pointer mismatch") + } + if absoluteSD.sacl != sacl { + panic("sacl pointer mismatch") + } + if absoluteSD.owner != owner { + panic("owner pointer mismatch") + } + if absoluteSD.group != group { + panic("group pointer mismatch") + } + absoluteSD.dacl = dacl + absoluteSD.sacl = sacl + absoluteSD.owner = owner + absoluteSD.group = group + return } diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 4a325438..bd513373 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -321,6 +321,8 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetConsoleOutputCP(cp uint32) (err error) = kernel32.SetConsoleOutputCP //sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW //sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW +//sys GetNumberOfConsoleInputEvents(console Handle, numevents *uint32) (err error) = kernel32.GetNumberOfConsoleInputEvents +//sys FlushConsoleInputBuffer(console Handle) (err error) = kernel32.FlushConsoleInputBuffer //sys resizePseudoConsole(pconsole Handle, size uint32) (hr error) = kernel32.ResizePseudoConsole //sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot //sys Module32First(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32FirstW @@ -870,6 +872,7 @@ const socket_error = uintptr(^uint32(0)) //sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom //sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo //sys WSASocket(af int32, typ int32, protocol int32, protoInfo *WSAProtocolInfo, group uint32, flags uint32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.WSASocketW +//sys WSADuplicateSocket(s Handle, processID uint32, info *WSAProtocolInfo) (err error) [failretval!=0] = ws2_32.WSADuplicateSocketW //sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname //sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname //sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs @@ -1698,8 +1701,9 @@ func NewNTUnicodeString(s string) (*NTUnicodeString, error) { // Slice returns a uint16 slice that aliases the data in the NTUnicodeString. func (s *NTUnicodeString) Slice() []uint16 { - slice := unsafe.Slice(s.Buffer, s.MaximumLength) - return slice[:s.Length] + // Note: this rounds the length down, if it happens + // to (incorrectly) be odd. Probably safer than rounding up. + return unsafe.Slice(s.Buffer, s.MaximumLength/2)[:s.Length/2] } func (s *NTUnicodeString) String() string { diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go index 9d138de5..358be3c7 100644 --- a/vendor/golang.org/x/sys/windows/types_windows.go +++ b/vendor/golang.org/x/sys/windows/types_windows.go @@ -65,6 +65,22 @@ var signals = [...]string{ 15: "terminated", } +// File flags for [os.OpenFile]. The O_ prefix is used to indicate +// that these flags are specific to the OpenFile function. +const ( + O_FILE_FLAG_OPEN_NO_RECALL = FILE_FLAG_OPEN_NO_RECALL + O_FILE_FLAG_OPEN_REPARSE_POINT = FILE_FLAG_OPEN_REPARSE_POINT + O_FILE_FLAG_SESSION_AWARE = FILE_FLAG_SESSION_AWARE + O_FILE_FLAG_POSIX_SEMANTICS = FILE_FLAG_POSIX_SEMANTICS + O_FILE_FLAG_BACKUP_SEMANTICS = FILE_FLAG_BACKUP_SEMANTICS + O_FILE_FLAG_DELETE_ON_CLOSE = FILE_FLAG_DELETE_ON_CLOSE + O_FILE_FLAG_SEQUENTIAL_SCAN = FILE_FLAG_SEQUENTIAL_SCAN + O_FILE_FLAG_RANDOM_ACCESS = FILE_FLAG_RANDOM_ACCESS + O_FILE_FLAG_NO_BUFFERING = FILE_FLAG_NO_BUFFERING + O_FILE_FLAG_OVERLAPPED = FILE_FLAG_OVERLAPPED + O_FILE_FLAG_WRITE_THROUGH = FILE_FLAG_WRITE_THROUGH +) + const ( FILE_READ_DATA = 0x00000001 FILE_READ_ATTRIBUTES = 0x00000080 @@ -1074,6 +1090,7 @@ const ( IP_ADD_MEMBERSHIP = 0xc IP_DROP_MEMBERSHIP = 0xd IP_PKTINFO = 0x13 + IP_MTU_DISCOVER = 0x47 IPV6_V6ONLY = 0x1b IPV6_UNICAST_HOPS = 0x4 @@ -1083,6 +1100,7 @@ const ( IPV6_JOIN_GROUP = 0xc IPV6_LEAVE_GROUP = 0xd IPV6_PKTINFO = 0x13 + IPV6_MTU_DISCOVER = 0x47 MSG_OOB = 0x1 MSG_PEEK = 0x2 @@ -1132,6 +1150,15 @@ const ( WSASYS_STATUS_LEN = 128 ) +// enum PMTUD_STATE from ws2ipdef.h +const ( + IP_PMTUDISC_NOT_SET = 0 + IP_PMTUDISC_DO = 1 + IP_PMTUDISC_DONT = 2 + IP_PMTUDISC_PROBE = 3 + IP_PMTUDISC_MAX = 4 +) + type WSABuf struct { Len uint32 Buf *byte @@ -1146,6 +1173,22 @@ type WSAMsg struct { Flags uint32 } +type WSACMSGHDR struct { + Len uintptr + Level int32 + Type int32 +} + +type IN_PKTINFO struct { + Addr [4]byte + Ifindex uint32 +} + +type IN6_PKTINFO struct { + Addr [16]byte + Ifindex uint32 +} + // Flags for WSASocket const ( WSA_FLAG_OVERLAPPED = 0x01 @@ -1949,6 +1992,12 @@ const ( SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1 ) +// FILE_ZERO_DATA_INFORMATION from winioctl.h +type FileZeroDataInformation struct { + FileOffset int64 + BeyondFinalZero int64 +} + const ( ComputerNameNetBIOS = 0 ComputerNameDnsHostname = 1 @@ -2673,6 +2722,8 @@ type CommTimeouts struct { // NTUnicodeString is a UTF-16 string for NT native APIs, corresponding to UNICODE_STRING. type NTUnicodeString struct { + // Note: Length and MaximumLength are in *bytes*, not uint16s. + // They should always be even. Length uint16 MaximumLength uint16 Buffer *uint16 @@ -3601,3 +3652,213 @@ const ( KLF_NOTELLSHELL = 0x00000080 KLF_SETFORPROCESS = 0x00000100 ) + +// Virtual Key codes +// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +const ( + VK_LBUTTON = 0x01 + VK_RBUTTON = 0x02 + VK_CANCEL = 0x03 + VK_MBUTTON = 0x04 + VK_XBUTTON1 = 0x05 + VK_XBUTTON2 = 0x06 + VK_BACK = 0x08 + VK_TAB = 0x09 + VK_CLEAR = 0x0C + VK_RETURN = 0x0D + VK_SHIFT = 0x10 + VK_CONTROL = 0x11 + VK_MENU = 0x12 + VK_PAUSE = 0x13 + VK_CAPITAL = 0x14 + VK_KANA = 0x15 + VK_HANGEUL = 0x15 + VK_HANGUL = 0x15 + VK_IME_ON = 0x16 + VK_JUNJA = 0x17 + VK_FINAL = 0x18 + VK_HANJA = 0x19 + VK_KANJI = 0x19 + VK_IME_OFF = 0x1A + VK_ESCAPE = 0x1B + VK_CONVERT = 0x1C + VK_NONCONVERT = 0x1D + VK_ACCEPT = 0x1E + VK_MODECHANGE = 0x1F + VK_SPACE = 0x20 + VK_PRIOR = 0x21 + VK_NEXT = 0x22 + VK_END = 0x23 + VK_HOME = 0x24 + VK_LEFT = 0x25 + VK_UP = 0x26 + VK_RIGHT = 0x27 + VK_DOWN = 0x28 + VK_SELECT = 0x29 + VK_PRINT = 0x2A + VK_EXECUTE = 0x2B + VK_SNAPSHOT = 0x2C + VK_INSERT = 0x2D + VK_DELETE = 0x2E + VK_HELP = 0x2F + VK_LWIN = 0x5B + VK_RWIN = 0x5C + VK_APPS = 0x5D + VK_SLEEP = 0x5F + VK_NUMPAD0 = 0x60 + VK_NUMPAD1 = 0x61 + VK_NUMPAD2 = 0x62 + VK_NUMPAD3 = 0x63 + VK_NUMPAD4 = 0x64 + VK_NUMPAD5 = 0x65 + VK_NUMPAD6 = 0x66 + VK_NUMPAD7 = 0x67 + VK_NUMPAD8 = 0x68 + VK_NUMPAD9 = 0x69 + VK_MULTIPLY = 0x6A + VK_ADD = 0x6B + VK_SEPARATOR = 0x6C + VK_SUBTRACT = 0x6D + VK_DECIMAL = 0x6E + VK_DIVIDE = 0x6F + VK_F1 = 0x70 + VK_F2 = 0x71 + VK_F3 = 0x72 + VK_F4 = 0x73 + VK_F5 = 0x74 + VK_F6 = 0x75 + VK_F7 = 0x76 + VK_F8 = 0x77 + VK_F9 = 0x78 + VK_F10 = 0x79 + VK_F11 = 0x7A + VK_F12 = 0x7B + VK_F13 = 0x7C + VK_F14 = 0x7D + VK_F15 = 0x7E + VK_F16 = 0x7F + VK_F17 = 0x80 + VK_F18 = 0x81 + VK_F19 = 0x82 + VK_F20 = 0x83 + VK_F21 = 0x84 + VK_F22 = 0x85 + VK_F23 = 0x86 + VK_F24 = 0x87 + VK_NUMLOCK = 0x90 + VK_SCROLL = 0x91 + VK_OEM_NEC_EQUAL = 0x92 + VK_OEM_FJ_JISHO = 0x92 + VK_OEM_FJ_MASSHOU = 0x93 + VK_OEM_FJ_TOUROKU = 0x94 + VK_OEM_FJ_LOYA = 0x95 + VK_OEM_FJ_ROYA = 0x96 + VK_LSHIFT = 0xA0 + VK_RSHIFT = 0xA1 + VK_LCONTROL = 0xA2 + VK_RCONTROL = 0xA3 + VK_LMENU = 0xA4 + VK_RMENU = 0xA5 + VK_BROWSER_BACK = 0xA6 + VK_BROWSER_FORWARD = 0xA7 + VK_BROWSER_REFRESH = 0xA8 + VK_BROWSER_STOP = 0xA9 + VK_BROWSER_SEARCH = 0xAA + VK_BROWSER_FAVORITES = 0xAB + VK_BROWSER_HOME = 0xAC + VK_VOLUME_MUTE = 0xAD + VK_VOLUME_DOWN = 0xAE + VK_VOLUME_UP = 0xAF + VK_MEDIA_NEXT_TRACK = 0xB0 + VK_MEDIA_PREV_TRACK = 0xB1 + VK_MEDIA_STOP = 0xB2 + VK_MEDIA_PLAY_PAUSE = 0xB3 + VK_LAUNCH_MAIL = 0xB4 + VK_LAUNCH_MEDIA_SELECT = 0xB5 + VK_LAUNCH_APP1 = 0xB6 + VK_LAUNCH_APP2 = 0xB7 + VK_OEM_1 = 0xBA + VK_OEM_PLUS = 0xBB + VK_OEM_COMMA = 0xBC + VK_OEM_MINUS = 0xBD + VK_OEM_PERIOD = 0xBE + VK_OEM_2 = 0xBF + VK_OEM_3 = 0xC0 + VK_OEM_4 = 0xDB + VK_OEM_5 = 0xDC + VK_OEM_6 = 0xDD + VK_OEM_7 = 0xDE + VK_OEM_8 = 0xDF + VK_OEM_AX = 0xE1 + VK_OEM_102 = 0xE2 + VK_ICO_HELP = 0xE3 + VK_ICO_00 = 0xE4 + VK_PROCESSKEY = 0xE5 + VK_ICO_CLEAR = 0xE6 + VK_OEM_RESET = 0xE9 + VK_OEM_JUMP = 0xEA + VK_OEM_PA1 = 0xEB + VK_OEM_PA2 = 0xEC + VK_OEM_PA3 = 0xED + VK_OEM_WSCTRL = 0xEE + VK_OEM_CUSEL = 0xEF + VK_OEM_ATTN = 0xF0 + VK_OEM_FINISH = 0xF1 + VK_OEM_COPY = 0xF2 + VK_OEM_AUTO = 0xF3 + VK_OEM_ENLW = 0xF4 + VK_OEM_BACKTAB = 0xF5 + VK_ATTN = 0xF6 + VK_CRSEL = 0xF7 + VK_EXSEL = 0xF8 + VK_EREOF = 0xF9 + VK_PLAY = 0xFA + VK_ZOOM = 0xFB + VK_NONAME = 0xFC + VK_PA1 = 0xFD + VK_OEM_CLEAR = 0xFE +) + +// Mouse button constants. +// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str +const ( + FROM_LEFT_1ST_BUTTON_PRESSED = 0x0001 + RIGHTMOST_BUTTON_PRESSED = 0x0002 + FROM_LEFT_2ND_BUTTON_PRESSED = 0x0004 + FROM_LEFT_3RD_BUTTON_PRESSED = 0x0008 + FROM_LEFT_4TH_BUTTON_PRESSED = 0x0010 +) + +// Control key state constaints. +// https://docs.microsoft.com/en-us/windows/console/key-event-record-str +// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str +const ( + CAPSLOCK_ON = 0x0080 + ENHANCED_KEY = 0x0100 + LEFT_ALT_PRESSED = 0x0002 + LEFT_CTRL_PRESSED = 0x0008 + NUMLOCK_ON = 0x0020 + RIGHT_ALT_PRESSED = 0x0001 + RIGHT_CTRL_PRESSED = 0x0004 + SCROLLLOCK_ON = 0x0040 + SHIFT_PRESSED = 0x0010 +) + +// Mouse event record event flags. +// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str +const ( + MOUSE_MOVED = 0x0001 + DOUBLE_CLICK = 0x0002 + MOUSE_WHEELED = 0x0004 + MOUSE_HWHEELED = 0x0008 +) + +// Input Record Event Types +// https://learn.microsoft.com/en-us/windows/console/input-record-str +const ( + FOCUS_EVENT = 0x0010 + KEY_EVENT = 0x0001 + MENU_EVENT = 0x0008 + MOUSE_EVENT = 0x0002 + WINDOW_BUFFER_SIZE_EVENT = 0x0004 +) diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 01c0716c..426151a0 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -238,6 +238,7 @@ var ( procFindResourceW = modkernel32.NewProc("FindResourceW") procFindVolumeClose = modkernel32.NewProc("FindVolumeClose") procFindVolumeMountPointClose = modkernel32.NewProc("FindVolumeMountPointClose") + procFlushConsoleInputBuffer = modkernel32.NewProc("FlushConsoleInputBuffer") procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers") procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile") procFormatMessageW = modkernel32.NewProc("FormatMessageW") @@ -284,6 +285,7 @@ var ( procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") procGetNamedPipeServerProcessId = modkernel32.NewProc("GetNamedPipeServerProcessId") + procGetNumberOfConsoleInputEvents = modkernel32.NewProc("GetNumberOfConsoleInputEvents") procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult") procGetPriorityClass = modkernel32.NewProc("GetPriorityClass") procGetProcAddress = modkernel32.NewProc("GetProcAddress") @@ -511,6 +513,7 @@ var ( procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW") procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW") procWSACleanup = modws2_32.NewProc("WSACleanup") + procWSADuplicateSocketW = modws2_32.NewProc("WSADuplicateSocketW") procWSAEnumProtocolsW = modws2_32.NewProc("WSAEnumProtocolsW") procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult") procWSAIoctl = modws2_32.NewProc("WSAIoctl") @@ -545,25 +548,25 @@ var ( ) func cm_Get_DevNode_Status(status *uint32, problemNumber *uint32, devInst DEVINST, flags uint32) (ret CONFIGRET) { - r0, _, _ := syscall.Syscall6(procCM_Get_DevNode_Status.Addr(), 4, uintptr(unsafe.Pointer(status)), uintptr(unsafe.Pointer(problemNumber)), uintptr(devInst), uintptr(flags), 0, 0) + r0, _, _ := syscall.SyscallN(procCM_Get_DevNode_Status.Addr(), uintptr(unsafe.Pointer(status)), uintptr(unsafe.Pointer(problemNumber)), uintptr(devInst), uintptr(flags)) ret = CONFIGRET(r0) return } func cm_Get_Device_Interface_List(interfaceClass *GUID, deviceID *uint16, buffer *uint16, bufferLen uint32, flags uint32) (ret CONFIGRET) { - r0, _, _ := syscall.Syscall6(procCM_Get_Device_Interface_ListW.Addr(), 5, uintptr(unsafe.Pointer(interfaceClass)), uintptr(unsafe.Pointer(deviceID)), uintptr(unsafe.Pointer(buffer)), uintptr(bufferLen), uintptr(flags), 0) + r0, _, _ := syscall.SyscallN(procCM_Get_Device_Interface_ListW.Addr(), uintptr(unsafe.Pointer(interfaceClass)), uintptr(unsafe.Pointer(deviceID)), uintptr(unsafe.Pointer(buffer)), uintptr(bufferLen), uintptr(flags)) ret = CONFIGRET(r0) return } func cm_Get_Device_Interface_List_Size(len *uint32, interfaceClass *GUID, deviceID *uint16, flags uint32) (ret CONFIGRET) { - r0, _, _ := syscall.Syscall6(procCM_Get_Device_Interface_List_SizeW.Addr(), 4, uintptr(unsafe.Pointer(len)), uintptr(unsafe.Pointer(interfaceClass)), uintptr(unsafe.Pointer(deviceID)), uintptr(flags), 0, 0) + r0, _, _ := syscall.SyscallN(procCM_Get_Device_Interface_List_SizeW.Addr(), uintptr(unsafe.Pointer(len)), uintptr(unsafe.Pointer(interfaceClass)), uintptr(unsafe.Pointer(deviceID)), uintptr(flags)) ret = CONFIGRET(r0) return } func cm_MapCrToWin32Err(configRet CONFIGRET, defaultWin32Error Errno) (ret Errno) { - r0, _, _ := syscall.Syscall(procCM_MapCrToWin32Err.Addr(), 2, uintptr(configRet), uintptr(defaultWin32Error), 0) + r0, _, _ := syscall.SyscallN(procCM_MapCrToWin32Err.Addr(), uintptr(configRet), uintptr(defaultWin32Error)) ret = Errno(r0) return } @@ -573,7 +576,7 @@ func AdjustTokenGroups(token Token, resetToDefault bool, newstate *Tokengroups, if resetToDefault { _p0 = 1 } - r1, _, e1 := syscall.Syscall6(procAdjustTokenGroups.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(newstate)), uintptr(buflen), uintptr(unsafe.Pointer(prevstate)), uintptr(unsafe.Pointer(returnlen))) + r1, _, e1 := syscall.SyscallN(procAdjustTokenGroups.Addr(), uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(newstate)), uintptr(buflen), uintptr(unsafe.Pointer(prevstate)), uintptr(unsafe.Pointer(returnlen))) if r1 == 0 { err = errnoErr(e1) } @@ -585,7 +588,7 @@ func AdjustTokenPrivileges(token Token, disableAllPrivileges bool, newstate *Tok if disableAllPrivileges { _p0 = 1 } - r1, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(newstate)), uintptr(buflen), uintptr(unsafe.Pointer(prevstate)), uintptr(unsafe.Pointer(returnlen))) + r1, _, e1 := syscall.SyscallN(procAdjustTokenPrivileges.Addr(), uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(newstate)), uintptr(buflen), uintptr(unsafe.Pointer(prevstate)), uintptr(unsafe.Pointer(returnlen))) if r1 == 0 { err = errnoErr(e1) } @@ -593,7 +596,7 @@ func AdjustTokenPrivileges(token Token, disableAllPrivileges bool, newstate *Tok } func AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) { - r1, _, e1 := syscall.Syscall12(procAllocateAndInitializeSid.Addr(), 11, uintptr(unsafe.Pointer(identAuth)), uintptr(subAuth), uintptr(subAuth0), uintptr(subAuth1), uintptr(subAuth2), uintptr(subAuth3), uintptr(subAuth4), uintptr(subAuth5), uintptr(subAuth6), uintptr(subAuth7), uintptr(unsafe.Pointer(sid)), 0) + r1, _, e1 := syscall.SyscallN(procAllocateAndInitializeSid.Addr(), uintptr(unsafe.Pointer(identAuth)), uintptr(subAuth), uintptr(subAuth0), uintptr(subAuth1), uintptr(subAuth2), uintptr(subAuth3), uintptr(subAuth4), uintptr(subAuth5), uintptr(subAuth6), uintptr(subAuth7), uintptr(unsafe.Pointer(sid))) if r1 == 0 { err = errnoErr(e1) } @@ -601,7 +604,7 @@ func AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, s } func buildSecurityDescriptor(owner *TRUSTEE, group *TRUSTEE, countAccessEntries uint32, accessEntries *EXPLICIT_ACCESS, countAuditEntries uint32, auditEntries *EXPLICIT_ACCESS, oldSecurityDescriptor *SECURITY_DESCRIPTOR, sizeNewSecurityDescriptor *uint32, newSecurityDescriptor **SECURITY_DESCRIPTOR) (ret error) { - r0, _, _ := syscall.Syscall9(procBuildSecurityDescriptorW.Addr(), 9, uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(countAccessEntries), uintptr(unsafe.Pointer(accessEntries)), uintptr(countAuditEntries), uintptr(unsafe.Pointer(auditEntries)), uintptr(unsafe.Pointer(oldSecurityDescriptor)), uintptr(unsafe.Pointer(sizeNewSecurityDescriptor)), uintptr(unsafe.Pointer(newSecurityDescriptor))) + r0, _, _ := syscall.SyscallN(procBuildSecurityDescriptorW.Addr(), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(countAccessEntries), uintptr(unsafe.Pointer(accessEntries)), uintptr(countAuditEntries), uintptr(unsafe.Pointer(auditEntries)), uintptr(unsafe.Pointer(oldSecurityDescriptor)), uintptr(unsafe.Pointer(sizeNewSecurityDescriptor)), uintptr(unsafe.Pointer(newSecurityDescriptor))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -609,7 +612,7 @@ func buildSecurityDescriptor(owner *TRUSTEE, group *TRUSTEE, countAccessEntries } func ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) { - r1, _, e1 := syscall.Syscall(procChangeServiceConfig2W.Addr(), 3, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(info))) + r1, _, e1 := syscall.SyscallN(procChangeServiceConfig2W.Addr(), uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(info))) if r1 == 0 { err = errnoErr(e1) } @@ -617,7 +620,7 @@ func ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err err } func ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) { - r1, _, e1 := syscall.Syscall12(procChangeServiceConfigW.Addr(), 11, uintptr(service), uintptr(serviceType), uintptr(startType), uintptr(errorControl), uintptr(unsafe.Pointer(binaryPathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), uintptr(unsafe.Pointer(displayName)), 0) + r1, _, e1 := syscall.SyscallN(procChangeServiceConfigW.Addr(), uintptr(service), uintptr(serviceType), uintptr(startType), uintptr(errorControl), uintptr(unsafe.Pointer(binaryPathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), uintptr(unsafe.Pointer(displayName))) if r1 == 0 { err = errnoErr(e1) } @@ -625,7 +628,7 @@ func ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, e } func checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) { - r1, _, e1 := syscall.Syscall(procCheckTokenMembership.Addr(), 3, uintptr(tokenHandle), uintptr(unsafe.Pointer(sidToCheck)), uintptr(unsafe.Pointer(isMember))) + r1, _, e1 := syscall.SyscallN(procCheckTokenMembership.Addr(), uintptr(tokenHandle), uintptr(unsafe.Pointer(sidToCheck)), uintptr(unsafe.Pointer(isMember))) if r1 == 0 { err = errnoErr(e1) } @@ -633,7 +636,7 @@ func checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) ( } func CloseServiceHandle(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procCloseServiceHandle.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procCloseServiceHandle.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -641,7 +644,7 @@ func CloseServiceHandle(handle Handle) (err error) { } func ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) { - r1, _, e1 := syscall.Syscall(procControlService.Addr(), 3, uintptr(service), uintptr(control), uintptr(unsafe.Pointer(status))) + r1, _, e1 := syscall.SyscallN(procControlService.Addr(), uintptr(service), uintptr(control), uintptr(unsafe.Pointer(status))) if r1 == 0 { err = errnoErr(e1) } @@ -649,7 +652,7 @@ func ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err } func convertSecurityDescriptorToStringSecurityDescriptor(sd *SECURITY_DESCRIPTOR, revision uint32, securityInformation SECURITY_INFORMATION, str **uint16, strLen *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(securityInformation), uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(strLen)), 0) + r1, _, e1 := syscall.SyscallN(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(securityInformation), uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(strLen))) if r1 == 0 { err = errnoErr(e1) } @@ -657,7 +660,7 @@ func convertSecurityDescriptorToStringSecurityDescriptor(sd *SECURITY_DESCRIPTOR } func ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) { - r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(stringSid)), 0) + r1, _, e1 := syscall.SyscallN(procConvertSidToStringSidW.Addr(), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(stringSid))) if r1 == 0 { err = errnoErr(e1) } @@ -674,7 +677,7 @@ func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision ui } func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd **SECURITY_DESCRIPTOR, size *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0) + r1, _, e1 := syscall.SyscallN(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size))) if r1 == 0 { err = errnoErr(e1) } @@ -682,7 +685,7 @@ func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision } func ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) { - r1, _, e1 := syscall.Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(stringSid)), uintptr(unsafe.Pointer(sid)), 0) + r1, _, e1 := syscall.SyscallN(procConvertStringSidToSidW.Addr(), uintptr(unsafe.Pointer(stringSid)), uintptr(unsafe.Pointer(sid))) if r1 == 0 { err = errnoErr(e1) } @@ -690,7 +693,7 @@ func ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) { } func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) { - r1, _, e1 := syscall.Syscall(procCopySid.Addr(), 3, uintptr(destSidLen), uintptr(unsafe.Pointer(destSid)), uintptr(unsafe.Pointer(srcSid))) + r1, _, e1 := syscall.SyscallN(procCopySid.Addr(), uintptr(destSidLen), uintptr(unsafe.Pointer(destSid)), uintptr(unsafe.Pointer(srcSid))) if r1 == 0 { err = errnoErr(e1) } @@ -702,7 +705,7 @@ func CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, proc if inheritHandles { _p0 = 1 } - r1, _, e1 := syscall.Syscall12(procCreateProcessAsUserW.Addr(), 11, uintptr(token), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0) + r1, _, e1 := syscall.SyscallN(procCreateProcessAsUserW.Addr(), uintptr(token), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo))) if r1 == 0 { err = errnoErr(e1) } @@ -710,7 +713,7 @@ func CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, proc } func CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall15(procCreateServiceW.Addr(), 13, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(unsafe.Pointer(displayName)), uintptr(access), uintptr(srvType), uintptr(startType), uintptr(errCtl), uintptr(unsafe.Pointer(pathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), 0, 0) + r0, _, e1 := syscall.SyscallN(procCreateServiceW.Addr(), uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(unsafe.Pointer(displayName)), uintptr(access), uintptr(srvType), uintptr(startType), uintptr(errCtl), uintptr(unsafe.Pointer(pathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password))) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -719,7 +722,7 @@ func CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access } func createWellKnownSid(sidType WELL_KNOWN_SID_TYPE, domainSid *SID, sid *SID, sizeSid *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procCreateWellKnownSid.Addr(), 4, uintptr(sidType), uintptr(unsafe.Pointer(domainSid)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sizeSid)), 0, 0) + r1, _, e1 := syscall.SyscallN(procCreateWellKnownSid.Addr(), uintptr(sidType), uintptr(unsafe.Pointer(domainSid)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sizeSid))) if r1 == 0 { err = errnoErr(e1) } @@ -727,7 +730,7 @@ func createWellKnownSid(sidType WELL_KNOWN_SID_TYPE, domainSid *SID, sid *SID, s } func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0) + r1, _, e1 := syscall.SyscallN(procCryptAcquireContextW.Addr(), uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags)) if r1 == 0 { err = errnoErr(e1) } @@ -735,7 +738,7 @@ func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16 } func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) { - r1, _, e1 := syscall.Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf))) + r1, _, e1 := syscall.SyscallN(procCryptGenRandom.Addr(), uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf))) if r1 == 0 { err = errnoErr(e1) } @@ -743,7 +746,7 @@ func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) { } func CryptReleaseContext(provhandle Handle, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0) + r1, _, e1 := syscall.SyscallN(procCryptReleaseContext.Addr(), uintptr(provhandle), uintptr(flags)) if r1 == 0 { err = errnoErr(e1) } @@ -751,7 +754,7 @@ func CryptReleaseContext(provhandle Handle, flags uint32) (err error) { } func DeleteService(service Handle) (err error) { - r1, _, e1 := syscall.Syscall(procDeleteService.Addr(), 1, uintptr(service), 0, 0) + r1, _, e1 := syscall.SyscallN(procDeleteService.Addr(), uintptr(service)) if r1 == 0 { err = errnoErr(e1) } @@ -759,7 +762,7 @@ func DeleteService(service Handle) (err error) { } func DeregisterEventSource(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procDeregisterEventSource.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procDeregisterEventSource.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -767,7 +770,7 @@ func DeregisterEventSource(handle Handle) (err error) { } func DuplicateTokenEx(existingToken Token, desiredAccess uint32, tokenAttributes *SecurityAttributes, impersonationLevel uint32, tokenType uint32, newToken *Token) (err error) { - r1, _, e1 := syscall.Syscall6(procDuplicateTokenEx.Addr(), 6, uintptr(existingToken), uintptr(desiredAccess), uintptr(unsafe.Pointer(tokenAttributes)), uintptr(impersonationLevel), uintptr(tokenType), uintptr(unsafe.Pointer(newToken))) + r1, _, e1 := syscall.SyscallN(procDuplicateTokenEx.Addr(), uintptr(existingToken), uintptr(desiredAccess), uintptr(unsafe.Pointer(tokenAttributes)), uintptr(impersonationLevel), uintptr(tokenType), uintptr(unsafe.Pointer(newToken))) if r1 == 0 { err = errnoErr(e1) } @@ -775,7 +778,7 @@ func DuplicateTokenEx(existingToken Token, desiredAccess uint32, tokenAttributes } func EnumDependentServices(service Handle, activityState uint32, services *ENUM_SERVICE_STATUS, buffSize uint32, bytesNeeded *uint32, servicesReturned *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procEnumDependentServicesW.Addr(), 6, uintptr(service), uintptr(activityState), uintptr(unsafe.Pointer(services)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), uintptr(unsafe.Pointer(servicesReturned))) + r1, _, e1 := syscall.SyscallN(procEnumDependentServicesW.Addr(), uintptr(service), uintptr(activityState), uintptr(unsafe.Pointer(services)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), uintptr(unsafe.Pointer(servicesReturned))) if r1 == 0 { err = errnoErr(e1) } @@ -783,7 +786,7 @@ func EnumDependentServices(service Handle, activityState uint32, services *ENUM_ } func EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) { - r1, _, e1 := syscall.Syscall12(procEnumServicesStatusExW.Addr(), 10, uintptr(mgr), uintptr(infoLevel), uintptr(serviceType), uintptr(serviceState), uintptr(unsafe.Pointer(services)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), uintptr(unsafe.Pointer(servicesReturned)), uintptr(unsafe.Pointer(resumeHandle)), uintptr(unsafe.Pointer(groupName)), 0, 0) + r1, _, e1 := syscall.SyscallN(procEnumServicesStatusExW.Addr(), uintptr(mgr), uintptr(infoLevel), uintptr(serviceType), uintptr(serviceState), uintptr(unsafe.Pointer(services)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), uintptr(unsafe.Pointer(servicesReturned)), uintptr(unsafe.Pointer(resumeHandle)), uintptr(unsafe.Pointer(groupName))) if r1 == 0 { err = errnoErr(e1) } @@ -791,13 +794,13 @@ func EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serv } func EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) { - r0, _, _ := syscall.Syscall(procEqualSid.Addr(), 2, uintptr(unsafe.Pointer(sid1)), uintptr(unsafe.Pointer(sid2)), 0) + r0, _, _ := syscall.SyscallN(procEqualSid.Addr(), uintptr(unsafe.Pointer(sid1)), uintptr(unsafe.Pointer(sid2))) isEqual = r0 != 0 return } func FreeSid(sid *SID) (err error) { - r1, _, e1 := syscall.Syscall(procFreeSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) + r1, _, e1 := syscall.SyscallN(procFreeSid.Addr(), uintptr(unsafe.Pointer(sid))) if r1 != 0 { err = errnoErr(e1) } @@ -805,7 +808,7 @@ func FreeSid(sid *SID) (err error) { } func GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (err error) { - r1, _, e1 := syscall.Syscall(procGetAce.Addr(), 3, uintptr(unsafe.Pointer(acl)), uintptr(aceIndex), uintptr(unsafe.Pointer(pAce))) + r1, _, e1 := syscall.SyscallN(procGetAce.Addr(), uintptr(unsafe.Pointer(acl)), uintptr(aceIndex), uintptr(unsafe.Pointer(pAce))) if r1 == 0 { err = errnoErr(e1) } @@ -813,7 +816,7 @@ func GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (err error) { } func GetLengthSid(sid *SID) (len uint32) { - r0, _, _ := syscall.Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) + r0, _, _ := syscall.SyscallN(procGetLengthSid.Addr(), uintptr(unsafe.Pointer(sid))) len = uint32(r0) return } @@ -828,7 +831,7 @@ func getNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, security } func _getNamedSecurityInfo(objectName *uint16, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner **SID, group **SID, dacl **ACL, sacl **ACL, sd **SECURITY_DESCRIPTOR) (ret error) { - r0, _, _ := syscall.Syscall9(procGetNamedSecurityInfoW.Addr(), 8, uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), uintptr(unsafe.Pointer(sd)), 0) + r0, _, _ := syscall.SyscallN(procGetNamedSecurityInfoW.Addr(), uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), uintptr(unsafe.Pointer(sd))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -836,7 +839,7 @@ func _getNamedSecurityInfo(objectName *uint16, objectType SE_OBJECT_TYPE, securi } func getSecurityDescriptorControl(sd *SECURITY_DESCRIPTOR, control *SECURITY_DESCRIPTOR_CONTROL, revision *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetSecurityDescriptorControl.Addr(), 3, uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(control)), uintptr(unsafe.Pointer(revision))) + r1, _, e1 := syscall.SyscallN(procGetSecurityDescriptorControl.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(control)), uintptr(unsafe.Pointer(revision))) if r1 == 0 { err = errnoErr(e1) } @@ -852,7 +855,7 @@ func getSecurityDescriptorDacl(sd *SECURITY_DESCRIPTOR, daclPresent *bool, dacl if *daclDefaulted { _p1 = 1 } - r1, _, e1 := syscall.Syscall6(procGetSecurityDescriptorDacl.Addr(), 4, uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(&_p0)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(&_p1)), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetSecurityDescriptorDacl.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(&_p0)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(&_p1))) *daclPresent = _p0 != 0 *daclDefaulted = _p1 != 0 if r1 == 0 { @@ -866,7 +869,7 @@ func getSecurityDescriptorGroup(sd *SECURITY_DESCRIPTOR, group **SID, groupDefau if *groupDefaulted { _p0 = 1 } - r1, _, e1 := syscall.Syscall(procGetSecurityDescriptorGroup.Addr(), 3, uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(&_p0))) + r1, _, e1 := syscall.SyscallN(procGetSecurityDescriptorGroup.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(&_p0))) *groupDefaulted = _p0 != 0 if r1 == 0 { err = errnoErr(e1) @@ -875,7 +878,7 @@ func getSecurityDescriptorGroup(sd *SECURITY_DESCRIPTOR, group **SID, groupDefau } func getSecurityDescriptorLength(sd *SECURITY_DESCRIPTOR) (len uint32) { - r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(unsafe.Pointer(sd)), 0, 0) + r0, _, _ := syscall.SyscallN(procGetSecurityDescriptorLength.Addr(), uintptr(unsafe.Pointer(sd))) len = uint32(r0) return } @@ -885,7 +888,7 @@ func getSecurityDescriptorOwner(sd *SECURITY_DESCRIPTOR, owner **SID, ownerDefau if *ownerDefaulted { _p0 = 1 } - r1, _, e1 := syscall.Syscall(procGetSecurityDescriptorOwner.Addr(), 3, uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(&_p0))) + r1, _, e1 := syscall.SyscallN(procGetSecurityDescriptorOwner.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(&_p0))) *ownerDefaulted = _p0 != 0 if r1 == 0 { err = errnoErr(e1) @@ -894,7 +897,7 @@ func getSecurityDescriptorOwner(sd *SECURITY_DESCRIPTOR, owner **SID, ownerDefau } func getSecurityDescriptorRMControl(sd *SECURITY_DESCRIPTOR, rmControl *uint8) (ret error) { - r0, _, _ := syscall.Syscall(procGetSecurityDescriptorRMControl.Addr(), 2, uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(rmControl)), 0) + r0, _, _ := syscall.SyscallN(procGetSecurityDescriptorRMControl.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(rmControl))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -910,7 +913,7 @@ func getSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent *bool, sacl if *saclDefaulted { _p1 = 1 } - r1, _, e1 := syscall.Syscall6(procGetSecurityDescriptorSacl.Addr(), 4, uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(&_p0)), uintptr(unsafe.Pointer(sacl)), uintptr(unsafe.Pointer(&_p1)), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetSecurityDescriptorSacl.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(&_p0)), uintptr(unsafe.Pointer(sacl)), uintptr(unsafe.Pointer(&_p1))) *saclPresent = _p0 != 0 *saclDefaulted = _p1 != 0 if r1 == 0 { @@ -920,7 +923,7 @@ func getSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent *bool, sacl } func getSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner **SID, group **SID, dacl **ACL, sacl **ACL, sd **SECURITY_DESCRIPTOR) (ret error) { - r0, _, _ := syscall.Syscall9(procGetSecurityInfo.Addr(), 8, uintptr(handle), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), uintptr(unsafe.Pointer(sd)), 0) + r0, _, _ := syscall.SyscallN(procGetSecurityInfo.Addr(), uintptr(handle), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), uintptr(unsafe.Pointer(sd))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -928,25 +931,25 @@ func getSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformati } func getSidIdentifierAuthority(sid *SID) (authority *SidIdentifierAuthority) { - r0, _, _ := syscall.Syscall(procGetSidIdentifierAuthority.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) + r0, _, _ := syscall.SyscallN(procGetSidIdentifierAuthority.Addr(), uintptr(unsafe.Pointer(sid))) authority = (*SidIdentifierAuthority)(unsafe.Pointer(r0)) return } func getSidSubAuthority(sid *SID, index uint32) (subAuthority *uint32) { - r0, _, _ := syscall.Syscall(procGetSidSubAuthority.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(index), 0) + r0, _, _ := syscall.SyscallN(procGetSidSubAuthority.Addr(), uintptr(unsafe.Pointer(sid)), uintptr(index)) subAuthority = (*uint32)(unsafe.Pointer(r0)) return } func getSidSubAuthorityCount(sid *SID) (count *uint8) { - r0, _, _ := syscall.Syscall(procGetSidSubAuthorityCount.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) + r0, _, _ := syscall.SyscallN(procGetSidSubAuthorityCount.Addr(), uintptr(unsafe.Pointer(sid))) count = (*uint8)(unsafe.Pointer(r0)) return } func GetTokenInformation(token Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetTokenInformation.Addr(), 5, uintptr(token), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), uintptr(unsafe.Pointer(returnedLen)), 0) + r1, _, e1 := syscall.SyscallN(procGetTokenInformation.Addr(), uintptr(token), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), uintptr(unsafe.Pointer(returnedLen))) if r1 == 0 { err = errnoErr(e1) } @@ -954,7 +957,7 @@ func GetTokenInformation(token Token, infoClass uint32, info *byte, infoLen uint } func ImpersonateSelf(impersonationlevel uint32) (err error) { - r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(impersonationlevel), 0, 0) + r1, _, e1 := syscall.SyscallN(procImpersonateSelf.Addr(), uintptr(impersonationlevel)) if r1 == 0 { err = errnoErr(e1) } @@ -962,7 +965,7 @@ func ImpersonateSelf(impersonationlevel uint32) (err error) { } func initializeSecurityDescriptor(absoluteSD *SECURITY_DESCRIPTOR, revision uint32) (err error) { - r1, _, e1 := syscall.Syscall(procInitializeSecurityDescriptor.Addr(), 2, uintptr(unsafe.Pointer(absoluteSD)), uintptr(revision), 0) + r1, _, e1 := syscall.SyscallN(procInitializeSecurityDescriptor.Addr(), uintptr(unsafe.Pointer(absoluteSD)), uintptr(revision)) if r1 == 0 { err = errnoErr(e1) } @@ -978,7 +981,7 @@ func InitiateSystemShutdownEx(machineName *uint16, message *uint16, timeout uint if rebootAfterShutdown { _p1 = 1 } - r1, _, e1 := syscall.Syscall6(procInitiateSystemShutdownExW.Addr(), 6, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(message)), uintptr(timeout), uintptr(_p0), uintptr(_p1), uintptr(reason)) + r1, _, e1 := syscall.SyscallN(procInitiateSystemShutdownExW.Addr(), uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(message)), uintptr(timeout), uintptr(_p0), uintptr(_p1), uintptr(reason)) if r1 == 0 { err = errnoErr(e1) } @@ -986,7 +989,7 @@ func InitiateSystemShutdownEx(machineName *uint16, message *uint16, timeout uint } func isTokenRestricted(tokenHandle Token) (ret bool, err error) { - r0, _, e1 := syscall.Syscall(procIsTokenRestricted.Addr(), 1, uintptr(tokenHandle), 0, 0) + r0, _, e1 := syscall.SyscallN(procIsTokenRestricted.Addr(), uintptr(tokenHandle)) ret = r0 != 0 if !ret { err = errnoErr(e1) @@ -995,25 +998,25 @@ func isTokenRestricted(tokenHandle Token) (ret bool, err error) { } func isValidSecurityDescriptor(sd *SECURITY_DESCRIPTOR) (isValid bool) { - r0, _, _ := syscall.Syscall(procIsValidSecurityDescriptor.Addr(), 1, uintptr(unsafe.Pointer(sd)), 0, 0) + r0, _, _ := syscall.SyscallN(procIsValidSecurityDescriptor.Addr(), uintptr(unsafe.Pointer(sd))) isValid = r0 != 0 return } func isValidSid(sid *SID) (isValid bool) { - r0, _, _ := syscall.Syscall(procIsValidSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) + r0, _, _ := syscall.SyscallN(procIsValidSid.Addr(), uintptr(unsafe.Pointer(sid))) isValid = r0 != 0 return } func isWellKnownSid(sid *SID, sidType WELL_KNOWN_SID_TYPE) (isWellKnown bool) { - r0, _, _ := syscall.Syscall(procIsWellKnownSid.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(sidType), 0) + r0, _, _ := syscall.SyscallN(procIsWellKnownSid.Addr(), uintptr(unsafe.Pointer(sid)), uintptr(sidType)) isWellKnown = r0 != 0 return } func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) + r1, _, e1 := syscall.SyscallN(procLookupAccountNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use))) if r1 == 0 { err = errnoErr(e1) } @@ -1021,7 +1024,7 @@ func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen } func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) + r1, _, e1 := syscall.SyscallN(procLookupAccountSidW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use))) if r1 == 0 { err = errnoErr(e1) } @@ -1029,7 +1032,7 @@ func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint3 } func LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) { - r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemname)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) + r1, _, e1 := syscall.SyscallN(procLookupPrivilegeValueW.Addr(), uintptr(unsafe.Pointer(systemname)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) if r1 == 0 { err = errnoErr(e1) } @@ -1037,7 +1040,7 @@ func LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err err } func makeAbsoluteSD(selfRelativeSD *SECURITY_DESCRIPTOR, absoluteSD *SECURITY_DESCRIPTOR, absoluteSDSize *uint32, dacl *ACL, daclSize *uint32, sacl *ACL, saclSize *uint32, owner *SID, ownerSize *uint32, group *SID, groupSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall12(procMakeAbsoluteSD.Addr(), 11, uintptr(unsafe.Pointer(selfRelativeSD)), uintptr(unsafe.Pointer(absoluteSD)), uintptr(unsafe.Pointer(absoluteSDSize)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(daclSize)), uintptr(unsafe.Pointer(sacl)), uintptr(unsafe.Pointer(saclSize)), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(ownerSize)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(groupSize)), 0) + r1, _, e1 := syscall.SyscallN(procMakeAbsoluteSD.Addr(), uintptr(unsafe.Pointer(selfRelativeSD)), uintptr(unsafe.Pointer(absoluteSD)), uintptr(unsafe.Pointer(absoluteSDSize)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(daclSize)), uintptr(unsafe.Pointer(sacl)), uintptr(unsafe.Pointer(saclSize)), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(ownerSize)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(groupSize))) if r1 == 0 { err = errnoErr(e1) } @@ -1045,7 +1048,7 @@ func makeAbsoluteSD(selfRelativeSD *SECURITY_DESCRIPTOR, absoluteSD *SECURITY_DE } func makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procMakeSelfRelativeSD.Addr(), 3, uintptr(unsafe.Pointer(absoluteSD)), uintptr(unsafe.Pointer(selfRelativeSD)), uintptr(unsafe.Pointer(selfRelativeSDSize))) + r1, _, e1 := syscall.SyscallN(procMakeSelfRelativeSD.Addr(), uintptr(unsafe.Pointer(absoluteSD)), uintptr(unsafe.Pointer(selfRelativeSD)), uintptr(unsafe.Pointer(selfRelativeSDSize))) if r1 == 0 { err = errnoErr(e1) } @@ -1053,7 +1056,7 @@ func makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURIT } func NotifyServiceStatusChange(service Handle, notifyMask uint32, notifier *SERVICE_NOTIFY) (ret error) { - r0, _, _ := syscall.Syscall(procNotifyServiceStatusChangeW.Addr(), 3, uintptr(service), uintptr(notifyMask), uintptr(unsafe.Pointer(notifier))) + r0, _, _ := syscall.SyscallN(procNotifyServiceStatusChangeW.Addr(), uintptr(service), uintptr(notifyMask), uintptr(unsafe.Pointer(notifier))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -1061,7 +1064,7 @@ func NotifyServiceStatusChange(service Handle, notifyMask uint32, notifier *SERV } func OpenProcessToken(process Handle, access uint32, token *Token) (err error) { - r1, _, e1 := syscall.Syscall(procOpenProcessToken.Addr(), 3, uintptr(process), uintptr(access), uintptr(unsafe.Pointer(token))) + r1, _, e1 := syscall.SyscallN(procOpenProcessToken.Addr(), uintptr(process), uintptr(access), uintptr(unsafe.Pointer(token))) if r1 == 0 { err = errnoErr(e1) } @@ -1069,7 +1072,7 @@ func OpenProcessToken(process Handle, access uint32, token *Token) (err error) { } func OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(access)) + r0, _, e1 := syscall.SyscallN(procOpenSCManagerW.Addr(), uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(access)) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -1078,7 +1081,7 @@ func OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (ha } func OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procOpenServiceW.Addr(), 3, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(access)) + r0, _, e1 := syscall.SyscallN(procOpenServiceW.Addr(), uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(access)) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -1091,7 +1094,7 @@ func OpenThreadToken(thread Handle, access uint32, openAsSelf bool, token *Token if openAsSelf { _p0 = 1 } - r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(access), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) + r1, _, e1 := syscall.SyscallN(procOpenThreadToken.Addr(), uintptr(thread), uintptr(access), uintptr(_p0), uintptr(unsafe.Pointer(token))) if r1 == 0 { err = errnoErr(e1) } @@ -1099,7 +1102,7 @@ func OpenThreadToken(thread Handle, access uint32, openAsSelf bool, token *Token } func QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procQueryServiceConfig2W.Addr(), 5, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(buff)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), 0) + r1, _, e1 := syscall.SyscallN(procQueryServiceConfig2W.Addr(), uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(buff)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded))) if r1 == 0 { err = errnoErr(e1) } @@ -1107,7 +1110,7 @@ func QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize } func QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procQueryServiceConfigW.Addr(), 4, uintptr(service), uintptr(unsafe.Pointer(serviceConfig)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), 0, 0) + r1, _, e1 := syscall.SyscallN(procQueryServiceConfigW.Addr(), uintptr(service), uintptr(unsafe.Pointer(serviceConfig)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded))) if r1 == 0 { err = errnoErr(e1) } @@ -1119,7 +1122,7 @@ func QueryServiceDynamicInformation(service Handle, infoLevel uint32, dynamicInf if err != nil { return } - r1, _, e1 := syscall.Syscall(procQueryServiceDynamicInformation.Addr(), 3, uintptr(service), uintptr(infoLevel), uintptr(dynamicInfo)) + r1, _, e1 := syscall.SyscallN(procQueryServiceDynamicInformation.Addr(), uintptr(service), uintptr(infoLevel), uintptr(dynamicInfo)) if r1 == 0 { err = errnoErr(e1) } @@ -1127,7 +1130,7 @@ func QueryServiceDynamicInformation(service Handle, infoLevel uint32, dynamicInf } func QueryServiceLockStatus(mgr Handle, lockStatus *QUERY_SERVICE_LOCK_STATUS, bufSize uint32, bytesNeeded *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procQueryServiceLockStatusW.Addr(), 4, uintptr(mgr), uintptr(unsafe.Pointer(lockStatus)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), 0, 0) + r1, _, e1 := syscall.SyscallN(procQueryServiceLockStatusW.Addr(), uintptr(mgr), uintptr(unsafe.Pointer(lockStatus)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded))) if r1 == 0 { err = errnoErr(e1) } @@ -1135,7 +1138,7 @@ func QueryServiceLockStatus(mgr Handle, lockStatus *QUERY_SERVICE_LOCK_STATUS, b } func QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) { - r1, _, e1 := syscall.Syscall(procQueryServiceStatus.Addr(), 2, uintptr(service), uintptr(unsafe.Pointer(status)), 0) + r1, _, e1 := syscall.SyscallN(procQueryServiceStatus.Addr(), uintptr(service), uintptr(unsafe.Pointer(status))) if r1 == 0 { err = errnoErr(e1) } @@ -1143,7 +1146,7 @@ func QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) { } func QueryServiceStatusEx(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procQueryServiceStatusEx.Addr(), 5, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(buff)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), 0) + r1, _, e1 := syscall.SyscallN(procQueryServiceStatusEx.Addr(), uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(buff)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded))) if r1 == 0 { err = errnoErr(e1) } @@ -1151,7 +1154,7 @@ func QueryServiceStatusEx(service Handle, infoLevel uint32, buff *byte, buffSize } func RegCloseKey(key Handle) (regerrno error) { - r0, _, _ := syscall.Syscall(procRegCloseKey.Addr(), 1, uintptr(key), 0, 0) + r0, _, _ := syscall.SyscallN(procRegCloseKey.Addr(), uintptr(key)) if r0 != 0 { regerrno = syscall.Errno(r0) } @@ -1159,7 +1162,7 @@ func RegCloseKey(key Handle) (regerrno error) { } func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) { - r0, _, _ := syscall.Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0) + r0, _, _ := syscall.SyscallN(procRegEnumKeyExW.Addr(), uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime))) if r0 != 0 { regerrno = syscall.Errno(r0) } @@ -1175,7 +1178,7 @@ func RegNotifyChangeKeyValue(key Handle, watchSubtree bool, notifyFilter uint32, if asynchronous { _p1 = 1 } - r0, _, _ := syscall.Syscall6(procRegNotifyChangeKeyValue.Addr(), 5, uintptr(key), uintptr(_p0), uintptr(notifyFilter), uintptr(event), uintptr(_p1), 0) + r0, _, _ := syscall.SyscallN(procRegNotifyChangeKeyValue.Addr(), uintptr(key), uintptr(_p0), uintptr(notifyFilter), uintptr(event), uintptr(_p1)) if r0 != 0 { regerrno = syscall.Errno(r0) } @@ -1183,7 +1186,7 @@ func RegNotifyChangeKeyValue(key Handle, watchSubtree bool, notifyFilter uint32, } func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) { - r0, _, _ := syscall.Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0) + r0, _, _ := syscall.SyscallN(procRegOpenKeyExW.Addr(), uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result))) if r0 != 0 { regerrno = syscall.Errno(r0) } @@ -1191,7 +1194,7 @@ func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint } func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) { - r0, _, _ := syscall.Syscall12(procRegQueryInfoKeyW.Addr(), 12, uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime))) + r0, _, _ := syscall.SyscallN(procRegQueryInfoKeyW.Addr(), uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime))) if r0 != 0 { regerrno = syscall.Errno(r0) } @@ -1199,7 +1202,7 @@ func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint } func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) { - r0, _, _ := syscall.Syscall6(procRegQueryValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen))) + r0, _, _ := syscall.SyscallN(procRegQueryValueExW.Addr(), uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen))) if r0 != 0 { regerrno = syscall.Errno(r0) } @@ -1207,7 +1210,7 @@ func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32 } func RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procRegisterEventSourceW.Addr(), 2, uintptr(unsafe.Pointer(uncServerName)), uintptr(unsafe.Pointer(sourceName)), 0) + r0, _, e1 := syscall.SyscallN(procRegisterEventSourceW.Addr(), uintptr(unsafe.Pointer(uncServerName)), uintptr(unsafe.Pointer(sourceName))) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -1216,7 +1219,7 @@ func RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Hand } func RegisterServiceCtrlHandlerEx(serviceName *uint16, handlerProc uintptr, context uintptr) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procRegisterServiceCtrlHandlerExW.Addr(), 3, uintptr(unsafe.Pointer(serviceName)), uintptr(handlerProc), uintptr(context)) + r0, _, e1 := syscall.SyscallN(procRegisterServiceCtrlHandlerExW.Addr(), uintptr(unsafe.Pointer(serviceName)), uintptr(handlerProc), uintptr(context)) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -1225,7 +1228,7 @@ func RegisterServiceCtrlHandlerEx(serviceName *uint16, handlerProc uintptr, cont } func ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) { - r1, _, e1 := syscall.Syscall9(procReportEventW.Addr(), 9, uintptr(log), uintptr(etype), uintptr(category), uintptr(eventId), uintptr(usrSId), uintptr(numStrings), uintptr(dataSize), uintptr(unsafe.Pointer(strings)), uintptr(unsafe.Pointer(rawData))) + r1, _, e1 := syscall.SyscallN(procReportEventW.Addr(), uintptr(log), uintptr(etype), uintptr(category), uintptr(eventId), uintptr(usrSId), uintptr(numStrings), uintptr(dataSize), uintptr(unsafe.Pointer(strings)), uintptr(unsafe.Pointer(rawData))) if r1 == 0 { err = errnoErr(e1) } @@ -1233,7 +1236,7 @@ func ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrS } func RevertToSelf() (err error) { - r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) + r1, _, e1 := syscall.SyscallN(procRevertToSelf.Addr()) if r1 == 0 { err = errnoErr(e1) } @@ -1241,7 +1244,7 @@ func RevertToSelf() (err error) { } func setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) { - r0, _, _ := syscall.Syscall6(procSetEntriesInAclW.Addr(), 4, uintptr(countExplicitEntries), uintptr(unsafe.Pointer(explicitEntries)), uintptr(unsafe.Pointer(oldACL)), uintptr(unsafe.Pointer(newACL)), 0, 0) + r0, _, _ := syscall.SyscallN(procSetEntriesInAclW.Addr(), uintptr(countExplicitEntries), uintptr(unsafe.Pointer(explicitEntries)), uintptr(unsafe.Pointer(oldACL)), uintptr(unsafe.Pointer(newACL))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -1249,7 +1252,7 @@ func setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCE } func SetKernelObjectSecurity(handle Handle, securityInformation SECURITY_INFORMATION, securityDescriptor *SECURITY_DESCRIPTOR) (err error) { - r1, _, e1 := syscall.Syscall(procSetKernelObjectSecurity.Addr(), 3, uintptr(handle), uintptr(securityInformation), uintptr(unsafe.Pointer(securityDescriptor))) + r1, _, e1 := syscall.SyscallN(procSetKernelObjectSecurity.Addr(), uintptr(handle), uintptr(securityInformation), uintptr(unsafe.Pointer(securityDescriptor))) if r1 == 0 { err = errnoErr(e1) } @@ -1266,7 +1269,7 @@ func SetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, security } func _SetNamedSecurityInfo(objectName *uint16, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) { - r0, _, _ := syscall.Syscall9(procSetNamedSecurityInfoW.Addr(), 7, uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0) + r0, _, _ := syscall.SyscallN(procSetNamedSecurityInfoW.Addr(), uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -1274,7 +1277,7 @@ func _SetNamedSecurityInfo(objectName *uint16, objectType SE_OBJECT_TYPE, securi } func setSecurityDescriptorControl(sd *SECURITY_DESCRIPTOR, controlBitsOfInterest SECURITY_DESCRIPTOR_CONTROL, controlBitsToSet SECURITY_DESCRIPTOR_CONTROL) (err error) { - r1, _, e1 := syscall.Syscall(procSetSecurityDescriptorControl.Addr(), 3, uintptr(unsafe.Pointer(sd)), uintptr(controlBitsOfInterest), uintptr(controlBitsToSet)) + r1, _, e1 := syscall.SyscallN(procSetSecurityDescriptorControl.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(controlBitsOfInterest), uintptr(controlBitsToSet)) if r1 == 0 { err = errnoErr(e1) } @@ -1290,7 +1293,7 @@ func setSecurityDescriptorDacl(sd *SECURITY_DESCRIPTOR, daclPresent bool, dacl * if daclDefaulted { _p1 = 1 } - r1, _, e1 := syscall.Syscall6(procSetSecurityDescriptorDacl.Addr(), 4, uintptr(unsafe.Pointer(sd)), uintptr(_p0), uintptr(unsafe.Pointer(dacl)), uintptr(_p1), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetSecurityDescriptorDacl.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(_p0), uintptr(unsafe.Pointer(dacl)), uintptr(_p1)) if r1 == 0 { err = errnoErr(e1) } @@ -1302,7 +1305,7 @@ func setSecurityDescriptorGroup(sd *SECURITY_DESCRIPTOR, group *SID, groupDefaul if groupDefaulted { _p0 = 1 } - r1, _, e1 := syscall.Syscall(procSetSecurityDescriptorGroup.Addr(), 3, uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(group)), uintptr(_p0)) + r1, _, e1 := syscall.SyscallN(procSetSecurityDescriptorGroup.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(group)), uintptr(_p0)) if r1 == 0 { err = errnoErr(e1) } @@ -1314,7 +1317,7 @@ func setSecurityDescriptorOwner(sd *SECURITY_DESCRIPTOR, owner *SID, ownerDefaul if ownerDefaulted { _p0 = 1 } - r1, _, e1 := syscall.Syscall(procSetSecurityDescriptorOwner.Addr(), 3, uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(owner)), uintptr(_p0)) + r1, _, e1 := syscall.SyscallN(procSetSecurityDescriptorOwner.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(owner)), uintptr(_p0)) if r1 == 0 { err = errnoErr(e1) } @@ -1322,7 +1325,7 @@ func setSecurityDescriptorOwner(sd *SECURITY_DESCRIPTOR, owner *SID, ownerDefaul } func setSecurityDescriptorRMControl(sd *SECURITY_DESCRIPTOR, rmControl *uint8) { - syscall.Syscall(procSetSecurityDescriptorRMControl.Addr(), 2, uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(rmControl)), 0) + syscall.SyscallN(procSetSecurityDescriptorRMControl.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(rmControl))) return } @@ -1335,7 +1338,7 @@ func setSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent bool, sacl * if saclDefaulted { _p1 = 1 } - r1, _, e1 := syscall.Syscall6(procSetSecurityDescriptorSacl.Addr(), 4, uintptr(unsafe.Pointer(sd)), uintptr(_p0), uintptr(unsafe.Pointer(sacl)), uintptr(_p1), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetSecurityDescriptorSacl.Addr(), uintptr(unsafe.Pointer(sd)), uintptr(_p0), uintptr(unsafe.Pointer(sacl)), uintptr(_p1)) if r1 == 0 { err = errnoErr(e1) } @@ -1343,7 +1346,7 @@ func setSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent bool, sacl * } func SetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) { - r0, _, _ := syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0) + r0, _, _ := syscall.SyscallN(procSetSecurityInfo.Addr(), uintptr(handle), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -1351,7 +1354,7 @@ func SetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformati } func SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) { - r1, _, e1 := syscall.Syscall(procSetServiceStatus.Addr(), 2, uintptr(service), uintptr(unsafe.Pointer(serviceStatus)), 0) + r1, _, e1 := syscall.SyscallN(procSetServiceStatus.Addr(), uintptr(service), uintptr(unsafe.Pointer(serviceStatus))) if r1 == 0 { err = errnoErr(e1) } @@ -1359,7 +1362,7 @@ func SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) } func SetThreadToken(thread *Handle, token Token) (err error) { - r1, _, e1 := syscall.Syscall(procSetThreadToken.Addr(), 2, uintptr(unsafe.Pointer(thread)), uintptr(token), 0) + r1, _, e1 := syscall.SyscallN(procSetThreadToken.Addr(), uintptr(unsafe.Pointer(thread)), uintptr(token)) if r1 == 0 { err = errnoErr(e1) } @@ -1367,7 +1370,7 @@ func SetThreadToken(thread *Handle, token Token) (err error) { } func SetTokenInformation(token Token, infoClass uint32, info *byte, infoLen uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetTokenInformation.Addr(), 4, uintptr(token), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetTokenInformation.Addr(), uintptr(token), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen)) if r1 == 0 { err = errnoErr(e1) } @@ -1375,7 +1378,7 @@ func SetTokenInformation(token Token, infoClass uint32, info *byte, infoLen uint } func StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) { - r1, _, e1 := syscall.Syscall(procStartServiceCtrlDispatcherW.Addr(), 1, uintptr(unsafe.Pointer(serviceTable)), 0, 0) + r1, _, e1 := syscall.SyscallN(procStartServiceCtrlDispatcherW.Addr(), uintptr(unsafe.Pointer(serviceTable))) if r1 == 0 { err = errnoErr(e1) } @@ -1383,7 +1386,7 @@ func StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) { } func StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) { - r1, _, e1 := syscall.Syscall(procStartServiceW.Addr(), 3, uintptr(service), uintptr(numArgs), uintptr(unsafe.Pointer(argVectors))) + r1, _, e1 := syscall.SyscallN(procStartServiceW.Addr(), uintptr(service), uintptr(numArgs), uintptr(unsafe.Pointer(argVectors))) if r1 == 0 { err = errnoErr(e1) } @@ -1391,7 +1394,7 @@ func StartService(service Handle, numArgs uint32, argVectors **uint16) (err erro } func CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) { - r1, _, e1 := syscall.Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0) + r1, _, e1 := syscall.SyscallN(procCertAddCertificateContextToStore.Addr(), uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext))) if r1 == 0 { err = errnoErr(e1) } @@ -1399,7 +1402,7 @@ func CertAddCertificateContextToStore(store Handle, certContext *CertContext, ad } func CertCloseStore(store Handle, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0) + r1, _, e1 := syscall.SyscallN(procCertCloseStore.Addr(), uintptr(store), uintptr(flags)) if r1 == 0 { err = errnoErr(e1) } @@ -1407,7 +1410,7 @@ func CertCloseStore(store Handle, flags uint32) (err error) { } func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) { - r0, _, e1 := syscall.Syscall(procCertCreateCertificateContext.Addr(), 3, uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen)) + r0, _, e1 := syscall.SyscallN(procCertCreateCertificateContext.Addr(), uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen)) context = (*CertContext)(unsafe.Pointer(r0)) if context == nil { err = errnoErr(e1) @@ -1416,7 +1419,7 @@ func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, en } func CertDeleteCertificateFromStore(certContext *CertContext) (err error) { - r1, _, e1 := syscall.Syscall(procCertDeleteCertificateFromStore.Addr(), 1, uintptr(unsafe.Pointer(certContext)), 0, 0) + r1, _, e1 := syscall.SyscallN(procCertDeleteCertificateFromStore.Addr(), uintptr(unsafe.Pointer(certContext))) if r1 == 0 { err = errnoErr(e1) } @@ -1424,13 +1427,13 @@ func CertDeleteCertificateFromStore(certContext *CertContext) (err error) { } func CertDuplicateCertificateContext(certContext *CertContext) (dupContext *CertContext) { - r0, _, _ := syscall.Syscall(procCertDuplicateCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(certContext)), 0, 0) + r0, _, _ := syscall.SyscallN(procCertDuplicateCertificateContext.Addr(), uintptr(unsafe.Pointer(certContext))) dupContext = (*CertContext)(unsafe.Pointer(r0)) return } func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) { - r0, _, e1 := syscall.Syscall(procCertEnumCertificatesInStore.Addr(), 2, uintptr(store), uintptr(unsafe.Pointer(prevContext)), 0) + r0, _, e1 := syscall.SyscallN(procCertEnumCertificatesInStore.Addr(), uintptr(store), uintptr(unsafe.Pointer(prevContext))) context = (*CertContext)(unsafe.Pointer(r0)) if context == nil { err = errnoErr(e1) @@ -1439,7 +1442,7 @@ func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (contex } func CertFindCertificateInStore(store Handle, certEncodingType uint32, findFlags uint32, findType uint32, findPara unsafe.Pointer, prevCertContext *CertContext) (cert *CertContext, err error) { - r0, _, e1 := syscall.Syscall6(procCertFindCertificateInStore.Addr(), 6, uintptr(store), uintptr(certEncodingType), uintptr(findFlags), uintptr(findType), uintptr(findPara), uintptr(unsafe.Pointer(prevCertContext))) + r0, _, e1 := syscall.SyscallN(procCertFindCertificateInStore.Addr(), uintptr(store), uintptr(certEncodingType), uintptr(findFlags), uintptr(findType), uintptr(findPara), uintptr(unsafe.Pointer(prevCertContext))) cert = (*CertContext)(unsafe.Pointer(r0)) if cert == nil { err = errnoErr(e1) @@ -1448,7 +1451,7 @@ func CertFindCertificateInStore(store Handle, certEncodingType uint32, findFlags } func CertFindChainInStore(store Handle, certEncodingType uint32, findFlags uint32, findType uint32, findPara unsafe.Pointer, prevChainContext *CertChainContext) (certchain *CertChainContext, err error) { - r0, _, e1 := syscall.Syscall6(procCertFindChainInStore.Addr(), 6, uintptr(store), uintptr(certEncodingType), uintptr(findFlags), uintptr(findType), uintptr(findPara), uintptr(unsafe.Pointer(prevChainContext))) + r0, _, e1 := syscall.SyscallN(procCertFindChainInStore.Addr(), uintptr(store), uintptr(certEncodingType), uintptr(findFlags), uintptr(findType), uintptr(findPara), uintptr(unsafe.Pointer(prevChainContext))) certchain = (*CertChainContext)(unsafe.Pointer(r0)) if certchain == nil { err = errnoErr(e1) @@ -1457,18 +1460,18 @@ func CertFindChainInStore(store Handle, certEncodingType uint32, findFlags uint3 } func CertFindExtension(objId *byte, countExtensions uint32, extensions *CertExtension) (ret *CertExtension) { - r0, _, _ := syscall.Syscall(procCertFindExtension.Addr(), 3, uintptr(unsafe.Pointer(objId)), uintptr(countExtensions), uintptr(unsafe.Pointer(extensions))) + r0, _, _ := syscall.SyscallN(procCertFindExtension.Addr(), uintptr(unsafe.Pointer(objId)), uintptr(countExtensions), uintptr(unsafe.Pointer(extensions))) ret = (*CertExtension)(unsafe.Pointer(r0)) return } func CertFreeCertificateChain(ctx *CertChainContext) { - syscall.Syscall(procCertFreeCertificateChain.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0) + syscall.SyscallN(procCertFreeCertificateChain.Addr(), uintptr(unsafe.Pointer(ctx))) return } func CertFreeCertificateContext(ctx *CertContext) (err error) { - r1, _, e1 := syscall.Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0) + r1, _, e1 := syscall.SyscallN(procCertFreeCertificateContext.Addr(), uintptr(unsafe.Pointer(ctx))) if r1 == 0 { err = errnoErr(e1) } @@ -1476,7 +1479,7 @@ func CertFreeCertificateContext(ctx *CertContext) (err error) { } func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) { - r1, _, e1 := syscall.Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0) + r1, _, e1 := syscall.SyscallN(procCertGetCertificateChain.Addr(), uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx))) if r1 == 0 { err = errnoErr(e1) } @@ -1484,13 +1487,13 @@ func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, a } func CertGetNameString(certContext *CertContext, nameType uint32, flags uint32, typePara unsafe.Pointer, name *uint16, size uint32) (chars uint32) { - r0, _, _ := syscall.Syscall6(procCertGetNameStringW.Addr(), 6, uintptr(unsafe.Pointer(certContext)), uintptr(nameType), uintptr(flags), uintptr(typePara), uintptr(unsafe.Pointer(name)), uintptr(size)) + r0, _, _ := syscall.SyscallN(procCertGetNameStringW.Addr(), uintptr(unsafe.Pointer(certContext)), uintptr(nameType), uintptr(flags), uintptr(typePara), uintptr(unsafe.Pointer(name)), uintptr(size)) chars = uint32(r0) return } func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0) + r0, _, e1 := syscall.SyscallN(procCertOpenStore.Addr(), uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para)) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -1499,7 +1502,7 @@ func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptPr } func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) { - r0, _, e1 := syscall.Syscall(procCertOpenSystemStoreW.Addr(), 2, uintptr(hprov), uintptr(unsafe.Pointer(name)), 0) + r0, _, e1 := syscall.SyscallN(procCertOpenSystemStoreW.Addr(), uintptr(hprov), uintptr(unsafe.Pointer(name))) store = Handle(r0) if store == 0 { err = errnoErr(e1) @@ -1508,7 +1511,7 @@ func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) { } func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) { - r1, _, e1 := syscall.Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0) + r1, _, e1 := syscall.SyscallN(procCertVerifyCertificateChainPolicy.Addr(), uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status))) if r1 == 0 { err = errnoErr(e1) } @@ -1520,7 +1523,7 @@ func CryptAcquireCertificatePrivateKey(cert *CertContext, flags uint32, paramete if *callerFreeProvOrNCryptKey { _p0 = 1 } - r1, _, e1 := syscall.Syscall6(procCryptAcquireCertificatePrivateKey.Addr(), 6, uintptr(unsafe.Pointer(cert)), uintptr(flags), uintptr(parameters), uintptr(unsafe.Pointer(cryptProvOrNCryptKey)), uintptr(unsafe.Pointer(keySpec)), uintptr(unsafe.Pointer(&_p0))) + r1, _, e1 := syscall.SyscallN(procCryptAcquireCertificatePrivateKey.Addr(), uintptr(unsafe.Pointer(cert)), uintptr(flags), uintptr(parameters), uintptr(unsafe.Pointer(cryptProvOrNCryptKey)), uintptr(unsafe.Pointer(keySpec)), uintptr(unsafe.Pointer(&_p0))) *callerFreeProvOrNCryptKey = _p0 != 0 if r1 == 0 { err = errnoErr(e1) @@ -1529,7 +1532,7 @@ func CryptAcquireCertificatePrivateKey(cert *CertContext, flags uint32, paramete } func CryptDecodeObject(encodingType uint32, structType *byte, encodedBytes *byte, lenEncodedBytes uint32, flags uint32, decoded unsafe.Pointer, decodedLen *uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procCryptDecodeObject.Addr(), 7, uintptr(encodingType), uintptr(unsafe.Pointer(structType)), uintptr(unsafe.Pointer(encodedBytes)), uintptr(lenEncodedBytes), uintptr(flags), uintptr(decoded), uintptr(unsafe.Pointer(decodedLen)), 0, 0) + r1, _, e1 := syscall.SyscallN(procCryptDecodeObject.Addr(), uintptr(encodingType), uintptr(unsafe.Pointer(structType)), uintptr(unsafe.Pointer(encodedBytes)), uintptr(lenEncodedBytes), uintptr(flags), uintptr(decoded), uintptr(unsafe.Pointer(decodedLen))) if r1 == 0 { err = errnoErr(e1) } @@ -1537,7 +1540,7 @@ func CryptDecodeObject(encodingType uint32, structType *byte, encodedBytes *byte } func CryptProtectData(dataIn *DataBlob, name *uint16, optionalEntropy *DataBlob, reserved uintptr, promptStruct *CryptProtectPromptStruct, flags uint32, dataOut *DataBlob) (err error) { - r1, _, e1 := syscall.Syscall9(procCryptProtectData.Addr(), 7, uintptr(unsafe.Pointer(dataIn)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(optionalEntropy)), uintptr(reserved), uintptr(unsafe.Pointer(promptStruct)), uintptr(flags), uintptr(unsafe.Pointer(dataOut)), 0, 0) + r1, _, e1 := syscall.SyscallN(procCryptProtectData.Addr(), uintptr(unsafe.Pointer(dataIn)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(optionalEntropy)), uintptr(reserved), uintptr(unsafe.Pointer(promptStruct)), uintptr(flags), uintptr(unsafe.Pointer(dataOut))) if r1 == 0 { err = errnoErr(e1) } @@ -1545,7 +1548,7 @@ func CryptProtectData(dataIn *DataBlob, name *uint16, optionalEntropy *DataBlob, } func CryptQueryObject(objectType uint32, object unsafe.Pointer, expectedContentTypeFlags uint32, expectedFormatTypeFlags uint32, flags uint32, msgAndCertEncodingType *uint32, contentType *uint32, formatType *uint32, certStore *Handle, msg *Handle, context *unsafe.Pointer) (err error) { - r1, _, e1 := syscall.Syscall12(procCryptQueryObject.Addr(), 11, uintptr(objectType), uintptr(object), uintptr(expectedContentTypeFlags), uintptr(expectedFormatTypeFlags), uintptr(flags), uintptr(unsafe.Pointer(msgAndCertEncodingType)), uintptr(unsafe.Pointer(contentType)), uintptr(unsafe.Pointer(formatType)), uintptr(unsafe.Pointer(certStore)), uintptr(unsafe.Pointer(msg)), uintptr(unsafe.Pointer(context)), 0) + r1, _, e1 := syscall.SyscallN(procCryptQueryObject.Addr(), uintptr(objectType), uintptr(object), uintptr(expectedContentTypeFlags), uintptr(expectedFormatTypeFlags), uintptr(flags), uintptr(unsafe.Pointer(msgAndCertEncodingType)), uintptr(unsafe.Pointer(contentType)), uintptr(unsafe.Pointer(formatType)), uintptr(unsafe.Pointer(certStore)), uintptr(unsafe.Pointer(msg)), uintptr(unsafe.Pointer(context))) if r1 == 0 { err = errnoErr(e1) } @@ -1553,7 +1556,7 @@ func CryptQueryObject(objectType uint32, object unsafe.Pointer, expectedContentT } func CryptUnprotectData(dataIn *DataBlob, name **uint16, optionalEntropy *DataBlob, reserved uintptr, promptStruct *CryptProtectPromptStruct, flags uint32, dataOut *DataBlob) (err error) { - r1, _, e1 := syscall.Syscall9(procCryptUnprotectData.Addr(), 7, uintptr(unsafe.Pointer(dataIn)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(optionalEntropy)), uintptr(reserved), uintptr(unsafe.Pointer(promptStruct)), uintptr(flags), uintptr(unsafe.Pointer(dataOut)), 0, 0) + r1, _, e1 := syscall.SyscallN(procCryptUnprotectData.Addr(), uintptr(unsafe.Pointer(dataIn)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(optionalEntropy)), uintptr(reserved), uintptr(unsafe.Pointer(promptStruct)), uintptr(flags), uintptr(unsafe.Pointer(dataOut))) if r1 == 0 { err = errnoErr(e1) } @@ -1561,7 +1564,7 @@ func CryptUnprotectData(dataIn *DataBlob, name **uint16, optionalEntropy *DataBl } func PFXImportCertStore(pfx *CryptDataBlob, password *uint16, flags uint32) (store Handle, err error) { - r0, _, e1 := syscall.Syscall(procPFXImportCertStore.Addr(), 3, uintptr(unsafe.Pointer(pfx)), uintptr(unsafe.Pointer(password)), uintptr(flags)) + r0, _, e1 := syscall.SyscallN(procPFXImportCertStore.Addr(), uintptr(unsafe.Pointer(pfx)), uintptr(unsafe.Pointer(password)), uintptr(flags)) store = Handle(r0) if store == 0 { err = errnoErr(e1) @@ -1570,7 +1573,7 @@ func PFXImportCertStore(pfx *CryptDataBlob, password *uint16, flags uint32) (sto } func DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) { - r0, _, _ := syscall.Syscall(procDnsNameCompare_W.Addr(), 2, uintptr(unsafe.Pointer(name1)), uintptr(unsafe.Pointer(name2)), 0) + r0, _, _ := syscall.SyscallN(procDnsNameCompare_W.Addr(), uintptr(unsafe.Pointer(name1)), uintptr(unsafe.Pointer(name2))) same = r0 != 0 return } @@ -1585,7 +1588,7 @@ func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSR } func _DnsQuery(name *uint16, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { - r0, _, _ := syscall.Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(name)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) + r0, _, _ := syscall.SyscallN(procDnsQuery_W.Addr(), uintptr(unsafe.Pointer(name)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) if r0 != 0 { status = syscall.Errno(r0) } @@ -1593,12 +1596,12 @@ func _DnsQuery(name *uint16, qtype uint16, options uint32, extra *byte, qrs **DN } func DnsRecordListFree(rl *DNSRecord, freetype uint32) { - syscall.Syscall(procDnsRecordListFree.Addr(), 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0) + syscall.SyscallN(procDnsRecordListFree.Addr(), uintptr(unsafe.Pointer(rl)), uintptr(freetype)) return } func DwmGetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) { - r0, _, _ := syscall.Syscall6(procDwmGetWindowAttribute.Addr(), 4, uintptr(hwnd), uintptr(attribute), uintptr(value), uintptr(size), 0, 0) + r0, _, _ := syscall.SyscallN(procDwmGetWindowAttribute.Addr(), uintptr(hwnd), uintptr(attribute), uintptr(value), uintptr(size)) if r0 != 0 { ret = syscall.Errno(r0) } @@ -1606,7 +1609,7 @@ func DwmGetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, si } func DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) { - r0, _, _ := syscall.Syscall6(procDwmSetWindowAttribute.Addr(), 4, uintptr(hwnd), uintptr(attribute), uintptr(value), uintptr(size), 0, 0) + r0, _, _ := syscall.SyscallN(procDwmSetWindowAttribute.Addr(), uintptr(hwnd), uintptr(attribute), uintptr(value), uintptr(size)) if r0 != 0 { ret = syscall.Errno(r0) } @@ -1614,7 +1617,7 @@ func DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, si } func CancelMibChangeNotify2(notificationHandle Handle) (errcode error) { - r0, _, _ := syscall.Syscall(procCancelMibChangeNotify2.Addr(), 1, uintptr(notificationHandle), 0, 0) + r0, _, _ := syscall.SyscallN(procCancelMibChangeNotify2.Addr(), uintptr(notificationHandle)) if r0 != 0 { errcode = syscall.Errno(r0) } @@ -1622,7 +1625,7 @@ func CancelMibChangeNotify2(notificationHandle Handle) (errcode error) { } func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) { - r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0) + r0, _, _ := syscall.SyscallN(procGetAdaptersAddresses.Addr(), uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer))) if r0 != 0 { errcode = syscall.Errno(r0) } @@ -1630,7 +1633,7 @@ func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapter } func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) { - r0, _, _ := syscall.Syscall(procGetAdaptersInfo.Addr(), 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0) + r0, _, _ := syscall.SyscallN(procGetAdaptersInfo.Addr(), uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol))) if r0 != 0 { errcode = syscall.Errno(r0) } @@ -1638,7 +1641,7 @@ func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) { } func getBestInterfaceEx(sockaddr unsafe.Pointer, pdwBestIfIndex *uint32) (errcode error) { - r0, _, _ := syscall.Syscall(procGetBestInterfaceEx.Addr(), 2, uintptr(sockaddr), uintptr(unsafe.Pointer(pdwBestIfIndex)), 0) + r0, _, _ := syscall.SyscallN(procGetBestInterfaceEx.Addr(), uintptr(sockaddr), uintptr(unsafe.Pointer(pdwBestIfIndex))) if r0 != 0 { errcode = syscall.Errno(r0) } @@ -1646,7 +1649,7 @@ func getBestInterfaceEx(sockaddr unsafe.Pointer, pdwBestIfIndex *uint32) (errcod } func GetIfEntry(pIfRow *MibIfRow) (errcode error) { - r0, _, _ := syscall.Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0) + r0, _, _ := syscall.SyscallN(procGetIfEntry.Addr(), uintptr(unsafe.Pointer(pIfRow))) if r0 != 0 { errcode = syscall.Errno(r0) } @@ -1654,7 +1657,7 @@ func GetIfEntry(pIfRow *MibIfRow) (errcode error) { } func GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) { - r0, _, _ := syscall.Syscall(procGetIfEntry2Ex.Addr(), 2, uintptr(level), uintptr(unsafe.Pointer(row)), 0) + r0, _, _ := syscall.SyscallN(procGetIfEntry2Ex.Addr(), uintptr(level), uintptr(unsafe.Pointer(row))) if r0 != 0 { errcode = syscall.Errno(r0) } @@ -1662,7 +1665,7 @@ func GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) { } func GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) { - r0, _, _ := syscall.Syscall(procGetUnicastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + r0, _, _ := syscall.SyscallN(procGetUnicastIpAddressEntry.Addr(), uintptr(unsafe.Pointer(row))) if r0 != 0 { errcode = syscall.Errno(r0) } @@ -1674,7 +1677,7 @@ func NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsa if initialNotification { _p0 = 1 } - r0, _, _ := syscall.Syscall6(procNotifyIpInterfaceChange.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0) + r0, _, _ := syscall.SyscallN(procNotifyIpInterfaceChange.Addr(), uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle))) if r0 != 0 { errcode = syscall.Errno(r0) } @@ -1686,7 +1689,7 @@ func NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext if initialNotification { _p0 = 1 } - r0, _, _ := syscall.Syscall6(procNotifyUnicastIpAddressChange.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0) + r0, _, _ := syscall.SyscallN(procNotifyUnicastIpAddressChange.Addr(), uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle))) if r0 != 0 { errcode = syscall.Errno(r0) } @@ -1694,7 +1697,7 @@ func NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext } func AddDllDirectory(path *uint16) (cookie uintptr, err error) { - r0, _, e1 := syscall.Syscall(procAddDllDirectory.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + r0, _, e1 := syscall.SyscallN(procAddDllDirectory.Addr(), uintptr(unsafe.Pointer(path))) cookie = uintptr(r0) if cookie == 0 { err = errnoErr(e1) @@ -1703,7 +1706,7 @@ func AddDllDirectory(path *uint16) (cookie uintptr, err error) { } func AssignProcessToJobObject(job Handle, process Handle) (err error) { - r1, _, e1 := syscall.Syscall(procAssignProcessToJobObject.Addr(), 2, uintptr(job), uintptr(process), 0) + r1, _, e1 := syscall.SyscallN(procAssignProcessToJobObject.Addr(), uintptr(job), uintptr(process)) if r1 == 0 { err = errnoErr(e1) } @@ -1711,7 +1714,7 @@ func AssignProcessToJobObject(job Handle, process Handle) (err error) { } func CancelIo(s Handle) (err error) { - r1, _, e1 := syscall.Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0) + r1, _, e1 := syscall.SyscallN(procCancelIo.Addr(), uintptr(s)) if r1 == 0 { err = errnoErr(e1) } @@ -1719,7 +1722,7 @@ func CancelIo(s Handle) (err error) { } func CancelIoEx(s Handle, o *Overlapped) (err error) { - r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(s), uintptr(unsafe.Pointer(o)), 0) + r1, _, e1 := syscall.SyscallN(procCancelIoEx.Addr(), uintptr(s), uintptr(unsafe.Pointer(o))) if r1 == 0 { err = errnoErr(e1) } @@ -1727,7 +1730,7 @@ func CancelIoEx(s Handle, o *Overlapped) (err error) { } func ClearCommBreak(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procClearCommBreak.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procClearCommBreak.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -1735,7 +1738,7 @@ func ClearCommBreak(handle Handle) (err error) { } func ClearCommError(handle Handle, lpErrors *uint32, lpStat *ComStat) (err error) { - r1, _, e1 := syscall.Syscall(procClearCommError.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(lpErrors)), uintptr(unsafe.Pointer(lpStat))) + r1, _, e1 := syscall.SyscallN(procClearCommError.Addr(), uintptr(handle), uintptr(unsafe.Pointer(lpErrors)), uintptr(unsafe.Pointer(lpStat))) if r1 == 0 { err = errnoErr(e1) } @@ -1743,7 +1746,7 @@ func ClearCommError(handle Handle, lpErrors *uint32, lpStat *ComStat) (err error } func CloseHandle(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procCloseHandle.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -1751,12 +1754,12 @@ func CloseHandle(handle Handle) (err error) { } func ClosePseudoConsole(console Handle) { - syscall.Syscall(procClosePseudoConsole.Addr(), 1, uintptr(console), 0, 0) + syscall.SyscallN(procClosePseudoConsole.Addr(), uintptr(console)) return } func ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error) { - r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(overlapped)), 0) + r1, _, e1 := syscall.SyscallN(procConnectNamedPipe.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(overlapped))) if r1 == 0 { err = errnoErr(e1) } @@ -1764,7 +1767,7 @@ func ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error) { } func CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) { - r1, _, e1 := syscall.Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0) + r1, _, e1 := syscall.SyscallN(procCreateDirectoryW.Addr(), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa))) if r1 == 0 { err = errnoErr(e1) } @@ -1772,7 +1775,7 @@ func CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) { } func CreateEventEx(eventAttrs *SecurityAttributes, name *uint16, flags uint32, desiredAccess uint32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall6(procCreateEventExW.Addr(), 4, uintptr(unsafe.Pointer(eventAttrs)), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(desiredAccess), 0, 0) + r0, _, e1 := syscall.SyscallN(procCreateEventExW.Addr(), uintptr(unsafe.Pointer(eventAttrs)), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(desiredAccess)) handle = Handle(r0) if handle == 0 || e1 == ERROR_ALREADY_EXISTS { err = errnoErr(e1) @@ -1781,7 +1784,7 @@ func CreateEventEx(eventAttrs *SecurityAttributes, name *uint16, flags uint32, d } func CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttrs)), uintptr(manualReset), uintptr(initialState), uintptr(unsafe.Pointer(name)), 0, 0) + r0, _, e1 := syscall.SyscallN(procCreateEventW.Addr(), uintptr(unsafe.Pointer(eventAttrs)), uintptr(manualReset), uintptr(initialState), uintptr(unsafe.Pointer(name))) handle = Handle(r0) if handle == 0 || e1 == ERROR_ALREADY_EXISTS { err = errnoErr(e1) @@ -1790,7 +1793,7 @@ func CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialStat } func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name))) + r0, _, e1 := syscall.SyscallN(procCreateFileMappingW.Addr(), uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name))) handle = Handle(r0) if handle == 0 || e1 == ERROR_ALREADY_EXISTS { err = errnoErr(e1) @@ -1799,7 +1802,7 @@ func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxS } func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile Handle) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) + r0, _, e1 := syscall.SyscallN(procCreateFileW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile)) handle = Handle(r0) if handle == InvalidHandle { err = errnoErr(e1) @@ -1808,7 +1811,7 @@ func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes } func CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) { - r1, _, e1 := syscall.Syscall(procCreateHardLinkW.Addr(), 3, uintptr(unsafe.Pointer(filename)), uintptr(unsafe.Pointer(existingfilename)), uintptr(reserved)) + r1, _, e1 := syscall.SyscallN(procCreateHardLinkW.Addr(), uintptr(unsafe.Pointer(filename)), uintptr(unsafe.Pointer(existingfilename)), uintptr(reserved)) if r1&0xff == 0 { err = errnoErr(e1) } @@ -1816,7 +1819,7 @@ func CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr } func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) + r0, _, e1 := syscall.SyscallN(procCreateIoCompletionPort.Addr(), uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt)) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -1825,7 +1828,7 @@ func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, thr } func CreateJobObject(jobAttr *SecurityAttributes, name *uint16) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procCreateJobObjectW.Addr(), 2, uintptr(unsafe.Pointer(jobAttr)), uintptr(unsafe.Pointer(name)), 0) + r0, _, e1 := syscall.SyscallN(procCreateJobObjectW.Addr(), uintptr(unsafe.Pointer(jobAttr)), uintptr(unsafe.Pointer(name))) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -1834,7 +1837,7 @@ func CreateJobObject(jobAttr *SecurityAttributes, name *uint16) (handle Handle, } func CreateMutexEx(mutexAttrs *SecurityAttributes, name *uint16, flags uint32, desiredAccess uint32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall6(procCreateMutexExW.Addr(), 4, uintptr(unsafe.Pointer(mutexAttrs)), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(desiredAccess), 0, 0) + r0, _, e1 := syscall.SyscallN(procCreateMutexExW.Addr(), uintptr(unsafe.Pointer(mutexAttrs)), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(desiredAccess)) handle = Handle(r0) if handle == 0 || e1 == ERROR_ALREADY_EXISTS { err = errnoErr(e1) @@ -1847,7 +1850,7 @@ func CreateMutex(mutexAttrs *SecurityAttributes, initialOwner bool, name *uint16 if initialOwner { _p0 = 1 } - r0, _, e1 := syscall.Syscall(procCreateMutexW.Addr(), 3, uintptr(unsafe.Pointer(mutexAttrs)), uintptr(_p0), uintptr(unsafe.Pointer(name))) + r0, _, e1 := syscall.SyscallN(procCreateMutexW.Addr(), uintptr(unsafe.Pointer(mutexAttrs)), uintptr(_p0), uintptr(unsafe.Pointer(name))) handle = Handle(r0) if handle == 0 || e1 == ERROR_ALREADY_EXISTS { err = errnoErr(e1) @@ -1856,7 +1859,7 @@ func CreateMutex(mutexAttrs *SecurityAttributes, initialOwner bool, name *uint16 } func CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *SecurityAttributes) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) + r0, _, e1 := syscall.SyscallN(procCreateNamedPipeW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa))) handle = Handle(r0) if handle == InvalidHandle { err = errnoErr(e1) @@ -1865,7 +1868,7 @@ func CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances u } func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0) + r1, _, e1 := syscall.SyscallN(procCreatePipe.Addr(), uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size)) if r1 == 0 { err = errnoErr(e1) } @@ -1877,7 +1880,7 @@ func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityA if inheritHandles { _p0 = 1 } - r1, _, e1 := syscall.Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0) + r1, _, e1 := syscall.SyscallN(procCreateProcessW.Addr(), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo))) if r1 == 0 { err = errnoErr(e1) } @@ -1885,7 +1888,7 @@ func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityA } func createPseudoConsole(size uint32, in Handle, out Handle, flags uint32, pconsole *Handle) (hr error) { - r0, _, _ := syscall.Syscall6(procCreatePseudoConsole.Addr(), 5, uintptr(size), uintptr(in), uintptr(out), uintptr(flags), uintptr(unsafe.Pointer(pconsole)), 0) + r0, _, _ := syscall.SyscallN(procCreatePseudoConsole.Addr(), uintptr(size), uintptr(in), uintptr(out), uintptr(flags), uintptr(unsafe.Pointer(pconsole))) if r0 != 0 { hr = syscall.Errno(r0) } @@ -1893,7 +1896,7 @@ func createPseudoConsole(size uint32, in Handle, out Handle, flags uint32, pcons } func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procCreateSymbolicLinkW.Addr(), 3, uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags)) + r1, _, e1 := syscall.SyscallN(procCreateSymbolicLinkW.Addr(), uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags)) if r1&0xff == 0 { err = errnoErr(e1) } @@ -1901,7 +1904,7 @@ func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags u } func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processId), 0) + r0, _, e1 := syscall.SyscallN(procCreateToolhelp32Snapshot.Addr(), uintptr(flags), uintptr(processId)) handle = Handle(r0) if handle == InvalidHandle { err = errnoErr(e1) @@ -1910,7 +1913,7 @@ func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, er } func DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procDefineDosDeviceW.Addr(), 3, uintptr(flags), uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath))) + r1, _, e1 := syscall.SyscallN(procDefineDosDeviceW.Addr(), uintptr(flags), uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath))) if r1 == 0 { err = errnoErr(e1) } @@ -1918,7 +1921,7 @@ func DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err } func DeleteFile(path *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + r1, _, e1 := syscall.SyscallN(procDeleteFileW.Addr(), uintptr(unsafe.Pointer(path))) if r1 == 0 { err = errnoErr(e1) } @@ -1926,12 +1929,12 @@ func DeleteFile(path *uint16) (err error) { } func deleteProcThreadAttributeList(attrlist *ProcThreadAttributeList) { - syscall.Syscall(procDeleteProcThreadAttributeList.Addr(), 1, uintptr(unsafe.Pointer(attrlist)), 0, 0) + syscall.SyscallN(procDeleteProcThreadAttributeList.Addr(), uintptr(unsafe.Pointer(attrlist))) return } func DeleteVolumeMountPoint(volumeMountPoint *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procDeleteVolumeMountPointW.Addr(), 1, uintptr(unsafe.Pointer(volumeMountPoint)), 0, 0) + r1, _, e1 := syscall.SyscallN(procDeleteVolumeMountPointW.Addr(), uintptr(unsafe.Pointer(volumeMountPoint))) if r1 == 0 { err = errnoErr(e1) } @@ -1939,7 +1942,7 @@ func DeleteVolumeMountPoint(volumeMountPoint *uint16) (err error) { } func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) { - r1, _, e1 := syscall.Syscall9(procDeviceIoControl.Addr(), 8, uintptr(handle), uintptr(ioControlCode), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferSize), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferSize), uintptr(unsafe.Pointer(bytesReturned)), uintptr(unsafe.Pointer(overlapped)), 0) + r1, _, e1 := syscall.SyscallN(procDeviceIoControl.Addr(), uintptr(handle), uintptr(ioControlCode), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferSize), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferSize), uintptr(unsafe.Pointer(bytesReturned)), uintptr(unsafe.Pointer(overlapped))) if r1 == 0 { err = errnoErr(e1) } @@ -1947,7 +1950,7 @@ func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBuff } func DisconnectNamedPipe(pipe Handle) (err error) { - r1, _, e1 := syscall.Syscall(procDisconnectNamedPipe.Addr(), 1, uintptr(pipe), 0, 0) + r1, _, e1 := syscall.SyscallN(procDisconnectNamedPipe.Addr(), uintptr(pipe)) if r1 == 0 { err = errnoErr(e1) } @@ -1959,7 +1962,7 @@ func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetP if bInheritHandle { _p0 = 1 } - r1, _, e1 := syscall.Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0) + r1, _, e1 := syscall.SyscallN(procDuplicateHandle.Addr(), uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions)) if r1 == 0 { err = errnoErr(e1) } @@ -1967,7 +1970,7 @@ func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetP } func EscapeCommFunction(handle Handle, dwFunc uint32) (err error) { - r1, _, e1 := syscall.Syscall(procEscapeCommFunction.Addr(), 2, uintptr(handle), uintptr(dwFunc), 0) + r1, _, e1 := syscall.SyscallN(procEscapeCommFunction.Addr(), uintptr(handle), uintptr(dwFunc)) if r1 == 0 { err = errnoErr(e1) } @@ -1975,12 +1978,12 @@ func EscapeCommFunction(handle Handle, dwFunc uint32) (err error) { } func ExitProcess(exitcode uint32) { - syscall.Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0) + syscall.SyscallN(procExitProcess.Addr(), uintptr(exitcode)) return } func ExpandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size)) + r0, _, e1 := syscall.SyscallN(procExpandEnvironmentStringsW.Addr(), uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size)) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -1989,7 +1992,7 @@ func ExpandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, } func FindClose(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procFindClose.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -1997,7 +2000,7 @@ func FindClose(handle Handle) (err error) { } func FindCloseChangeNotification(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procFindCloseChangeNotification.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procFindCloseChangeNotification.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -2018,7 +2021,7 @@ func _FindFirstChangeNotification(path *uint16, watchSubtree bool, notifyFilter if watchSubtree { _p1 = 1 } - r0, _, e1 := syscall.Syscall(procFindFirstChangeNotificationW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(_p1), uintptr(notifyFilter)) + r0, _, e1 := syscall.SyscallN(procFindFirstChangeNotificationW.Addr(), uintptr(unsafe.Pointer(path)), uintptr(_p1), uintptr(notifyFilter)) handle = Handle(r0) if handle == InvalidHandle { err = errnoErr(e1) @@ -2027,7 +2030,7 @@ func _FindFirstChangeNotification(path *uint16, watchSubtree bool, notifyFilter } func findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procFindFirstFileW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0) + r0, _, e1 := syscall.SyscallN(procFindFirstFileW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data))) handle = Handle(r0) if handle == InvalidHandle { err = errnoErr(e1) @@ -2036,7 +2039,7 @@ func findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err erro } func FindFirstVolumeMountPoint(rootPathName *uint16, volumeMountPoint *uint16, bufferLength uint32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procFindFirstVolumeMountPointW.Addr(), 3, uintptr(unsafe.Pointer(rootPathName)), uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(bufferLength)) + r0, _, e1 := syscall.SyscallN(procFindFirstVolumeMountPointW.Addr(), uintptr(unsafe.Pointer(rootPathName)), uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(bufferLength)) handle = Handle(r0) if handle == InvalidHandle { err = errnoErr(e1) @@ -2045,7 +2048,7 @@ func FindFirstVolumeMountPoint(rootPathName *uint16, volumeMountPoint *uint16, b } func FindFirstVolume(volumeName *uint16, bufferLength uint32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procFindFirstVolumeW.Addr(), 2, uintptr(unsafe.Pointer(volumeName)), uintptr(bufferLength), 0) + r0, _, e1 := syscall.SyscallN(procFindFirstVolumeW.Addr(), uintptr(unsafe.Pointer(volumeName)), uintptr(bufferLength)) handle = Handle(r0) if handle == InvalidHandle { err = errnoErr(e1) @@ -2054,7 +2057,7 @@ func FindFirstVolume(volumeName *uint16, bufferLength uint32) (handle Handle, er } func FindNextChangeNotification(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procFindNextChangeNotification.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procFindNextChangeNotification.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -2062,7 +2065,7 @@ func FindNextChangeNotification(handle Handle) (err error) { } func findNextFile1(handle Handle, data *win32finddata1) (err error) { - r1, _, e1 := syscall.Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) + r1, _, e1 := syscall.SyscallN(procFindNextFileW.Addr(), uintptr(handle), uintptr(unsafe.Pointer(data))) if r1 == 0 { err = errnoErr(e1) } @@ -2070,7 +2073,7 @@ func findNextFile1(handle Handle, data *win32finddata1) (err error) { } func FindNextVolumeMountPoint(findVolumeMountPoint Handle, volumeMountPoint *uint16, bufferLength uint32) (err error) { - r1, _, e1 := syscall.Syscall(procFindNextVolumeMountPointW.Addr(), 3, uintptr(findVolumeMountPoint), uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(bufferLength)) + r1, _, e1 := syscall.SyscallN(procFindNextVolumeMountPointW.Addr(), uintptr(findVolumeMountPoint), uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(bufferLength)) if r1 == 0 { err = errnoErr(e1) } @@ -2078,7 +2081,7 @@ func FindNextVolumeMountPoint(findVolumeMountPoint Handle, volumeMountPoint *uin } func FindNextVolume(findVolume Handle, volumeName *uint16, bufferLength uint32) (err error) { - r1, _, e1 := syscall.Syscall(procFindNextVolumeW.Addr(), 3, uintptr(findVolume), uintptr(unsafe.Pointer(volumeName)), uintptr(bufferLength)) + r1, _, e1 := syscall.SyscallN(procFindNextVolumeW.Addr(), uintptr(findVolume), uintptr(unsafe.Pointer(volumeName)), uintptr(bufferLength)) if r1 == 0 { err = errnoErr(e1) } @@ -2086,7 +2089,7 @@ func FindNextVolume(findVolume Handle, volumeName *uint16, bufferLength uint32) } func findResource(module Handle, name uintptr, resType uintptr) (resInfo Handle, err error) { - r0, _, e1 := syscall.Syscall(procFindResourceW.Addr(), 3, uintptr(module), uintptr(name), uintptr(resType)) + r0, _, e1 := syscall.SyscallN(procFindResourceW.Addr(), uintptr(module), uintptr(name), uintptr(resType)) resInfo = Handle(r0) if resInfo == 0 { err = errnoErr(e1) @@ -2095,7 +2098,7 @@ func findResource(module Handle, name uintptr, resType uintptr) (resInfo Handle, } func FindVolumeClose(findVolume Handle) (err error) { - r1, _, e1 := syscall.Syscall(procFindVolumeClose.Addr(), 1, uintptr(findVolume), 0, 0) + r1, _, e1 := syscall.SyscallN(procFindVolumeClose.Addr(), uintptr(findVolume)) if r1 == 0 { err = errnoErr(e1) } @@ -2103,7 +2106,15 @@ func FindVolumeClose(findVolume Handle) (err error) { } func FindVolumeMountPointClose(findVolumeMountPoint Handle) (err error) { - r1, _, e1 := syscall.Syscall(procFindVolumeMountPointClose.Addr(), 1, uintptr(findVolumeMountPoint), 0, 0) + r1, _, e1 := syscall.SyscallN(procFindVolumeMountPointClose.Addr(), uintptr(findVolumeMountPoint)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func FlushConsoleInputBuffer(console Handle) (err error) { + r1, _, e1 := syscall.SyscallN(procFlushConsoleInputBuffer.Addr(), uintptr(console)) if r1 == 0 { err = errnoErr(e1) } @@ -2111,7 +2122,7 @@ func FindVolumeMountPointClose(findVolumeMountPoint Handle) (err error) { } func FlushFileBuffers(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procFlushFileBuffers.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -2119,7 +2130,7 @@ func FlushFileBuffers(handle Handle) (err error) { } func FlushViewOfFile(addr uintptr, length uintptr) (err error) { - r1, _, e1 := syscall.Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0) + r1, _, e1 := syscall.SyscallN(procFlushViewOfFile.Addr(), uintptr(addr), uintptr(length)) if r1 == 0 { err = errnoErr(e1) } @@ -2131,7 +2142,7 @@ func FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, bu if len(buf) > 0 { _p0 = &buf[0] } - r0, _, e1 := syscall.Syscall9(procFormatMessageW.Addr(), 7, uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args)), 0, 0) + r0, _, e1 := syscall.SyscallN(procFormatMessageW.Addr(), uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args))) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2140,7 +2151,7 @@ func FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, bu } func FreeEnvironmentStrings(envs *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0) + r1, _, e1 := syscall.SyscallN(procFreeEnvironmentStringsW.Addr(), uintptr(unsafe.Pointer(envs))) if r1 == 0 { err = errnoErr(e1) } @@ -2148,7 +2159,7 @@ func FreeEnvironmentStrings(envs *uint16) (err error) { } func FreeLibrary(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procFreeLibrary.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -2156,7 +2167,7 @@ func FreeLibrary(handle Handle) (err error) { } func GenerateConsoleCtrlEvent(ctrlEvent uint32, processGroupID uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGenerateConsoleCtrlEvent.Addr(), 2, uintptr(ctrlEvent), uintptr(processGroupID), 0) + r1, _, e1 := syscall.SyscallN(procGenerateConsoleCtrlEvent.Addr(), uintptr(ctrlEvent), uintptr(processGroupID)) if r1 == 0 { err = errnoErr(e1) } @@ -2164,19 +2175,19 @@ func GenerateConsoleCtrlEvent(ctrlEvent uint32, processGroupID uint32) (err erro } func GetACP() (acp uint32) { - r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procGetACP.Addr()) acp = uint32(r0) return } func GetActiveProcessorCount(groupNumber uint16) (ret uint32) { - r0, _, _ := syscall.Syscall(procGetActiveProcessorCount.Addr(), 1, uintptr(groupNumber), 0, 0) + r0, _, _ := syscall.SyscallN(procGetActiveProcessorCount.Addr(), uintptr(groupNumber)) ret = uint32(r0) return } func GetCommModemStatus(handle Handle, lpModemStat *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetCommModemStatus.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpModemStat)), 0) + r1, _, e1 := syscall.SyscallN(procGetCommModemStatus.Addr(), uintptr(handle), uintptr(unsafe.Pointer(lpModemStat))) if r1 == 0 { err = errnoErr(e1) } @@ -2184,7 +2195,7 @@ func GetCommModemStatus(handle Handle, lpModemStat *uint32) (err error) { } func GetCommState(handle Handle, lpDCB *DCB) (err error) { - r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpDCB)), 0) + r1, _, e1 := syscall.SyscallN(procGetCommState.Addr(), uintptr(handle), uintptr(unsafe.Pointer(lpDCB))) if r1 == 0 { err = errnoErr(e1) } @@ -2192,7 +2203,7 @@ func GetCommState(handle Handle, lpDCB *DCB) (err error) { } func GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { - r1, _, e1 := syscall.Syscall(procGetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) + r1, _, e1 := syscall.SyscallN(procGetCommTimeouts.Addr(), uintptr(handle), uintptr(unsafe.Pointer(timeouts))) if r1 == 0 { err = errnoErr(e1) } @@ -2200,13 +2211,13 @@ func GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { } func GetCommandLine() (cmd *uint16) { - r0, _, _ := syscall.Syscall(procGetCommandLineW.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procGetCommandLineW.Addr()) cmd = (*uint16)(unsafe.Pointer(r0)) return } func GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nametype), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n))) + r1, _, e1 := syscall.SyscallN(procGetComputerNameExW.Addr(), uintptr(nametype), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n))) if r1 == 0 { err = errnoErr(e1) } @@ -2214,7 +2225,7 @@ func GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) { } func GetComputerName(buf *uint16, n *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0) + r1, _, e1 := syscall.SyscallN(procGetComputerNameW.Addr(), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n))) if r1 == 0 { err = errnoErr(e1) } @@ -2222,7 +2233,7 @@ func GetComputerName(buf *uint16, n *uint32) (err error) { } func GetConsoleCP() (cp uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0) + r0, _, e1 := syscall.SyscallN(procGetConsoleCP.Addr()) cp = uint32(r0) if cp == 0 { err = errnoErr(e1) @@ -2231,7 +2242,7 @@ func GetConsoleCP() (cp uint32, err error) { } func GetConsoleMode(console Handle, mode *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0) + r1, _, e1 := syscall.SyscallN(procGetConsoleMode.Addr(), uintptr(console), uintptr(unsafe.Pointer(mode))) if r1 == 0 { err = errnoErr(e1) } @@ -2239,7 +2250,7 @@ func GetConsoleMode(console Handle, mode *uint32) (err error) { } func GetConsoleOutputCP() (cp uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetConsoleOutputCP.Addr(), 0, 0, 0, 0) + r0, _, e1 := syscall.SyscallN(procGetConsoleOutputCP.Addr()) cp = uint32(r0) if cp == 0 { err = errnoErr(e1) @@ -2248,7 +2259,7 @@ func GetConsoleOutputCP() (cp uint32, err error) { } func GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) { - r1, _, e1 := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(info)), 0) + r1, _, e1 := syscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(console), uintptr(unsafe.Pointer(info))) if r1 == 0 { err = errnoErr(e1) } @@ -2256,7 +2267,7 @@ func GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) ( } func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetCurrentDirectoryW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + r0, _, e1 := syscall.SyscallN(procGetCurrentDirectoryW.Addr(), uintptr(buflen), uintptr(unsafe.Pointer(buf))) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2265,19 +2276,19 @@ func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) { } func GetCurrentProcessId() (pid uint32) { - r0, _, _ := syscall.Syscall(procGetCurrentProcessId.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procGetCurrentProcessId.Addr()) pid = uint32(r0) return } func GetCurrentThreadId() (id uint32) { - r0, _, _ := syscall.Syscall(procGetCurrentThreadId.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procGetCurrentThreadId.Addr()) id = uint32(r0) return } func GetDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailableToCaller *uint64, totalNumberOfBytes *uint64, totalNumberOfFreeBytes *uint64) (err error) { - r1, _, e1 := syscall.Syscall6(procGetDiskFreeSpaceExW.Addr(), 4, uintptr(unsafe.Pointer(directoryName)), uintptr(unsafe.Pointer(freeBytesAvailableToCaller)), uintptr(unsafe.Pointer(totalNumberOfBytes)), uintptr(unsafe.Pointer(totalNumberOfFreeBytes)), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetDiskFreeSpaceExW.Addr(), uintptr(unsafe.Pointer(directoryName)), uintptr(unsafe.Pointer(freeBytesAvailableToCaller)), uintptr(unsafe.Pointer(totalNumberOfBytes)), uintptr(unsafe.Pointer(totalNumberOfFreeBytes))) if r1 == 0 { err = errnoErr(e1) } @@ -2285,13 +2296,13 @@ func GetDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailableToCaller *uint6 } func GetDriveType(rootPathName *uint16) (driveType uint32) { - r0, _, _ := syscall.Syscall(procGetDriveTypeW.Addr(), 1, uintptr(unsafe.Pointer(rootPathName)), 0, 0) + r0, _, _ := syscall.SyscallN(procGetDriveTypeW.Addr(), uintptr(unsafe.Pointer(rootPathName))) driveType = uint32(r0) return } func GetEnvironmentStrings() (envs *uint16, err error) { - r0, _, e1 := syscall.Syscall(procGetEnvironmentStringsW.Addr(), 0, 0, 0, 0) + r0, _, e1 := syscall.SyscallN(procGetEnvironmentStringsW.Addr()) envs = (*uint16)(unsafe.Pointer(r0)) if envs == nil { err = errnoErr(e1) @@ -2300,7 +2311,7 @@ func GetEnvironmentStrings() (envs *uint16, err error) { } func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetEnvironmentVariableW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size)) + r0, _, e1 := syscall.SyscallN(procGetEnvironmentVariableW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size)) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2309,7 +2320,7 @@ func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32 } func GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0) + r1, _, e1 := syscall.SyscallN(procGetExitCodeProcess.Addr(), uintptr(handle), uintptr(unsafe.Pointer(exitcode))) if r1 == 0 { err = errnoErr(e1) } @@ -2317,7 +2328,7 @@ func GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) { } func GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) { - r1, _, e1 := syscall.Syscall(procGetFileAttributesExW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(level), uintptr(unsafe.Pointer(info))) + r1, _, e1 := syscall.SyscallN(procGetFileAttributesExW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(level), uintptr(unsafe.Pointer(info))) if r1 == 0 { err = errnoErr(e1) } @@ -2325,7 +2336,7 @@ func GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) { } func GetFileAttributes(name *uint16) (attrs uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetFileAttributesW.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + r0, _, e1 := syscall.SyscallN(procGetFileAttributesW.Addr(), uintptr(unsafe.Pointer(name))) attrs = uint32(r0) if attrs == INVALID_FILE_ATTRIBUTES { err = errnoErr(e1) @@ -2334,7 +2345,7 @@ func GetFileAttributes(name *uint16) (attrs uint32, err error) { } func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) { - r1, _, e1 := syscall.Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) + r1, _, e1 := syscall.SyscallN(procGetFileInformationByHandle.Addr(), uintptr(handle), uintptr(unsafe.Pointer(data))) if r1 == 0 { err = errnoErr(e1) } @@ -2342,7 +2353,7 @@ func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (e } func GetFileInformationByHandleEx(handle Handle, class uint32, outBuffer *byte, outBufferLen uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(handle), uintptr(class), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferLen), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetFileInformationByHandleEx.Addr(), uintptr(handle), uintptr(class), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferLen)) if r1 == 0 { err = errnoErr(e1) } @@ -2350,7 +2361,7 @@ func GetFileInformationByHandleEx(handle Handle, class uint32, outBuffer *byte, } func GetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) { - r1, _, e1 := syscall.Syscall6(procGetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetFileTime.Addr(), uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime))) if r1 == 0 { err = errnoErr(e1) } @@ -2358,7 +2369,7 @@ func GetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetim } func GetFileType(filehandle Handle) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0) + r0, _, e1 := syscall.SyscallN(procGetFileType.Addr(), uintptr(filehandle)) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2367,7 +2378,7 @@ func GetFileType(filehandle Handle) (n uint32, err error) { } func GetFinalPathNameByHandle(file Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall6(procGetFinalPathNameByHandleW.Addr(), 4, uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags), 0, 0) + r0, _, e1 := syscall.SyscallN(procGetFinalPathNameByHandleW.Addr(), uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags)) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2376,7 +2387,7 @@ func GetFinalPathNameByHandle(file Handle, filePath *uint16, filePathSize uint32 } func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) { - r0, _, e1 := syscall.Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0) + r0, _, e1 := syscall.SyscallN(procGetFullPathNameW.Addr(), uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname))) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2385,13 +2396,13 @@ func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) ( } func GetLargePageMinimum() (size uintptr) { - r0, _, _ := syscall.Syscall(procGetLargePageMinimum.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procGetLargePageMinimum.Addr()) size = uintptr(r0) return } func GetLastError() (lasterr error) { - r0, _, _ := syscall.Syscall(procGetLastError.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procGetLastError.Addr()) if r0 != 0 { lasterr = syscall.Errno(r0) } @@ -2399,7 +2410,7 @@ func GetLastError() (lasterr error) { } func GetLogicalDriveStrings(bufferLength uint32, buffer *uint16) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetLogicalDriveStringsW.Addr(), 2, uintptr(bufferLength), uintptr(unsafe.Pointer(buffer)), 0) + r0, _, e1 := syscall.SyscallN(procGetLogicalDriveStringsW.Addr(), uintptr(bufferLength), uintptr(unsafe.Pointer(buffer))) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2408,7 +2419,7 @@ func GetLogicalDriveStrings(bufferLength uint32, buffer *uint16) (n uint32, err } func GetLogicalDrives() (drivesBitMask uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetLogicalDrives.Addr(), 0, 0, 0, 0) + r0, _, e1 := syscall.SyscallN(procGetLogicalDrives.Addr()) drivesBitMask = uint32(r0) if drivesBitMask == 0 { err = errnoErr(e1) @@ -2417,7 +2428,7 @@ func GetLogicalDrives() (drivesBitMask uint32, err error) { } func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen)) + r0, _, e1 := syscall.SyscallN(procGetLongPathNameW.Addr(), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen)) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2426,13 +2437,13 @@ func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err er } func GetMaximumProcessorCount(groupNumber uint16) (ret uint32) { - r0, _, _ := syscall.Syscall(procGetMaximumProcessorCount.Addr(), 1, uintptr(groupNumber), 0, 0) + r0, _, _ := syscall.SyscallN(procGetMaximumProcessorCount.Addr(), uintptr(groupNumber)) ret = uint32(r0) return } func GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetModuleFileNameW.Addr(), 3, uintptr(module), uintptr(unsafe.Pointer(filename)), uintptr(size)) + r0, _, e1 := syscall.SyscallN(procGetModuleFileNameW.Addr(), uintptr(module), uintptr(unsafe.Pointer(filename)), uintptr(size)) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2441,7 +2452,7 @@ func GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, } func GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err error) { - r1, _, e1 := syscall.Syscall(procGetModuleHandleExW.Addr(), 3, uintptr(flags), uintptr(unsafe.Pointer(moduleName)), uintptr(unsafe.Pointer(module))) + r1, _, e1 := syscall.SyscallN(procGetModuleHandleExW.Addr(), uintptr(flags), uintptr(unsafe.Pointer(moduleName)), uintptr(unsafe.Pointer(module))) if r1 == 0 { err = errnoErr(e1) } @@ -2449,7 +2460,7 @@ func GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err er } func GetNamedPipeClientProcessId(pipe Handle, clientProcessID *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetNamedPipeClientProcessId.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(clientProcessID)), 0) + r1, _, e1 := syscall.SyscallN(procGetNamedPipeClientProcessId.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(clientProcessID))) if r1 == 0 { err = errnoErr(e1) } @@ -2457,7 +2468,7 @@ func GetNamedPipeClientProcessId(pipe Handle, clientProcessID *uint32) (err erro } func GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetNamedPipeHandleStateW.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize)) if r1 == 0 { err = errnoErr(e1) } @@ -2465,7 +2476,7 @@ func GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, m } func GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) + r1, _, e1 := syscall.SyscallN(procGetNamedPipeInfo.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances))) if r1 == 0 { err = errnoErr(e1) } @@ -2473,7 +2484,15 @@ func GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint3 } func GetNamedPipeServerProcessId(pipe Handle, serverProcessID *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetNamedPipeServerProcessId.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(serverProcessID)), 0) + r1, _, e1 := syscall.SyscallN(procGetNamedPipeServerProcessId.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(serverProcessID))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func GetNumberOfConsoleInputEvents(console Handle, numevents *uint32) (err error) { + r1, _, e1 := syscall.SyscallN(procGetNumberOfConsoleInputEvents.Addr(), uintptr(console), uintptr(unsafe.Pointer(numevents))) if r1 == 0 { err = errnoErr(e1) } @@ -2485,7 +2504,7 @@ func GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wa if wait { _p0 = 1 } - r1, _, e1 := syscall.Syscall6(procGetOverlappedResult.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(done)), uintptr(_p0), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetOverlappedResult.Addr(), uintptr(handle), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(done)), uintptr(_p0)) if r1 == 0 { err = errnoErr(e1) } @@ -2493,7 +2512,7 @@ func GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wa } func GetPriorityClass(process Handle) (ret uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetPriorityClass.Addr(), 1, uintptr(process), 0, 0) + r0, _, e1 := syscall.SyscallN(procGetPriorityClass.Addr(), uintptr(process)) ret = uint32(r0) if ret == 0 { err = errnoErr(e1) @@ -2511,7 +2530,7 @@ func GetProcAddress(module Handle, procname string) (proc uintptr, err error) { } func _GetProcAddress(module Handle, procname *byte) (proc uintptr, err error) { - r0, _, e1 := syscall.Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(procname)), 0) + r0, _, e1 := syscall.SyscallN(procGetProcAddress.Addr(), uintptr(module), uintptr(unsafe.Pointer(procname))) proc = uintptr(r0) if proc == 0 { err = errnoErr(e1) @@ -2520,7 +2539,7 @@ func _GetProcAddress(module Handle, procname *byte) (proc uintptr, err error) { } func GetProcessId(process Handle) (id uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetProcessId.Addr(), 1, uintptr(process), 0, 0) + r0, _, e1 := syscall.SyscallN(procGetProcessId.Addr(), uintptr(process)) id = uint32(r0) if id == 0 { err = errnoErr(e1) @@ -2529,7 +2548,7 @@ func GetProcessId(process Handle) (id uint32, err error) { } func getProcessPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetProcessPreferredUILanguages.Addr(), 4, uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize)), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetProcessPreferredUILanguages.Addr(), uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize))) if r1 == 0 { err = errnoErr(e1) } @@ -2537,7 +2556,7 @@ func getProcessPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uin } func GetProcessShutdownParameters(level *uint32, flags *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetProcessShutdownParameters.Addr(), 2, uintptr(unsafe.Pointer(level)), uintptr(unsafe.Pointer(flags)), 0) + r1, _, e1 := syscall.SyscallN(procGetProcessShutdownParameters.Addr(), uintptr(unsafe.Pointer(level)), uintptr(unsafe.Pointer(flags))) if r1 == 0 { err = errnoErr(e1) } @@ -2545,7 +2564,7 @@ func GetProcessShutdownParameters(level *uint32, flags *uint32) (err error) { } func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) { - r1, _, e1 := syscall.Syscall6(procGetProcessTimes.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(creationTime)), uintptr(unsafe.Pointer(exitTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime)), 0) + r1, _, e1 := syscall.SyscallN(procGetProcessTimes.Addr(), uintptr(handle), uintptr(unsafe.Pointer(creationTime)), uintptr(unsafe.Pointer(exitTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime))) if r1 == 0 { err = errnoErr(e1) } @@ -2553,12 +2572,12 @@ func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, } func GetProcessWorkingSetSizeEx(hProcess Handle, lpMinimumWorkingSetSize *uintptr, lpMaximumWorkingSetSize *uintptr, flags *uint32) { - syscall.Syscall6(procGetProcessWorkingSetSizeEx.Addr(), 4, uintptr(hProcess), uintptr(unsafe.Pointer(lpMinimumWorkingSetSize)), uintptr(unsafe.Pointer(lpMaximumWorkingSetSize)), uintptr(unsafe.Pointer(flags)), 0, 0) + syscall.SyscallN(procGetProcessWorkingSetSizeEx.Addr(), uintptr(hProcess), uintptr(unsafe.Pointer(lpMinimumWorkingSetSize)), uintptr(unsafe.Pointer(lpMaximumWorkingSetSize)), uintptr(unsafe.Pointer(flags))) return } func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0) + r1, _, e1 := syscall.SyscallN(procGetQueuedCompletionStatus.Addr(), uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout)) if r1 == 0 { err = errnoErr(e1) } @@ -2566,7 +2585,7 @@ func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overl } func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetShortPathNameW.Addr(), 3, uintptr(unsafe.Pointer(longpath)), uintptr(unsafe.Pointer(shortpath)), uintptr(buflen)) + r0, _, e1 := syscall.SyscallN(procGetShortPathNameW.Addr(), uintptr(unsafe.Pointer(longpath)), uintptr(unsafe.Pointer(shortpath)), uintptr(buflen)) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2575,12 +2594,12 @@ func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uin } func getStartupInfo(startupInfo *StartupInfo) { - syscall.Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0) + syscall.SyscallN(procGetStartupInfoW.Addr(), uintptr(unsafe.Pointer(startupInfo))) return } func GetStdHandle(stdhandle uint32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procGetStdHandle.Addr(), 1, uintptr(stdhandle), 0, 0) + r0, _, e1 := syscall.SyscallN(procGetStdHandle.Addr(), uintptr(stdhandle)) handle = Handle(r0) if handle == InvalidHandle { err = errnoErr(e1) @@ -2589,7 +2608,7 @@ func GetStdHandle(stdhandle uint32) (handle Handle, err error) { } func getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetSystemDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(dirLen), 0) + r0, _, e1 := syscall.SyscallN(procGetSystemDirectoryW.Addr(), uintptr(unsafe.Pointer(dir)), uintptr(dirLen)) len = uint32(r0) if len == 0 { err = errnoErr(e1) @@ -2598,7 +2617,7 @@ func getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) { } func getSystemPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetSystemPreferredUILanguages.Addr(), 4, uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize)), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetSystemPreferredUILanguages.Addr(), uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize))) if r1 == 0 { err = errnoErr(e1) } @@ -2606,17 +2625,17 @@ func getSystemPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint } func GetSystemTimeAsFileTime(time *Filetime) { - syscall.Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0) + syscall.SyscallN(procGetSystemTimeAsFileTime.Addr(), uintptr(unsafe.Pointer(time))) return } func GetSystemTimePreciseAsFileTime(time *Filetime) { - syscall.Syscall(procGetSystemTimePreciseAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0) + syscall.SyscallN(procGetSystemTimePreciseAsFileTime.Addr(), uintptr(unsafe.Pointer(time))) return } func getSystemWindowsDirectory(dir *uint16, dirLen uint32) (len uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetSystemWindowsDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(dirLen), 0) + r0, _, e1 := syscall.SyscallN(procGetSystemWindowsDirectoryW.Addr(), uintptr(unsafe.Pointer(dir)), uintptr(dirLen)) len = uint32(r0) if len == 0 { err = errnoErr(e1) @@ -2625,7 +2644,7 @@ func getSystemWindowsDirectory(dir *uint16, dirLen uint32) (len uint32, err erro } func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + r0, _, e1 := syscall.SyscallN(procGetTempPathW.Addr(), uintptr(buflen), uintptr(unsafe.Pointer(buf))) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2634,7 +2653,7 @@ func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) { } func getThreadPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetThreadPreferredUILanguages.Addr(), 4, uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize)), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetThreadPreferredUILanguages.Addr(), uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize))) if r1 == 0 { err = errnoErr(e1) } @@ -2642,13 +2661,13 @@ func getThreadPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint } func getTickCount64() (ms uint64) { - r0, _, _ := syscall.Syscall(procGetTickCount64.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procGetTickCount64.Addr()) ms = uint64(r0) return } func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0) + r0, _, e1 := syscall.SyscallN(procGetTimeZoneInformation.Addr(), uintptr(unsafe.Pointer(tzi))) rc = uint32(r0) if rc == 0xffffffff { err = errnoErr(e1) @@ -2657,7 +2676,7 @@ func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) { } func getUserPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetUserPreferredUILanguages.Addr(), 4, uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize)), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetUserPreferredUILanguages.Addr(), uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize))) if r1 == 0 { err = errnoErr(e1) } @@ -2665,7 +2684,7 @@ func getUserPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16 } func GetVersion() (ver uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetVersion.Addr(), 0, 0, 0, 0) + r0, _, e1 := syscall.SyscallN(procGetVersion.Addr()) ver = uint32(r0) if ver == 0 { err = errnoErr(e1) @@ -2674,7 +2693,7 @@ func GetVersion() (ver uint32, err error) { } func GetVolumeInformationByHandle(file Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procGetVolumeInformationByHandleW.Addr(), 8, uintptr(file), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize), 0) + r1, _, e1 := syscall.SyscallN(procGetVolumeInformationByHandleW.Addr(), uintptr(file), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize)) if r1 == 0 { err = errnoErr(e1) } @@ -2682,7 +2701,7 @@ func GetVolumeInformationByHandle(file Handle, volumeNameBuffer *uint16, volumeN } func GetVolumeInformation(rootPathName *uint16, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procGetVolumeInformationW.Addr(), 8, uintptr(unsafe.Pointer(rootPathName)), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize), 0) + r1, _, e1 := syscall.SyscallN(procGetVolumeInformationW.Addr(), uintptr(unsafe.Pointer(rootPathName)), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize)) if r1 == 0 { err = errnoErr(e1) } @@ -2690,7 +2709,7 @@ func GetVolumeInformation(rootPathName *uint16, volumeNameBuffer *uint16, volume } func GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16, bufferlength uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetVolumeNameForVolumeMountPointW.Addr(), 3, uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(unsafe.Pointer(volumeName)), uintptr(bufferlength)) + r1, _, e1 := syscall.SyscallN(procGetVolumeNameForVolumeMountPointW.Addr(), uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(unsafe.Pointer(volumeName)), uintptr(bufferlength)) if r1 == 0 { err = errnoErr(e1) } @@ -2698,7 +2717,7 @@ func GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint } func GetVolumePathName(fileName *uint16, volumePathName *uint16, bufferLength uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetVolumePathNameW.Addr(), 3, uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(volumePathName)), uintptr(bufferLength)) + r1, _, e1 := syscall.SyscallN(procGetVolumePathNameW.Addr(), uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(volumePathName)), uintptr(bufferLength)) if r1 == 0 { err = errnoErr(e1) } @@ -2706,7 +2725,7 @@ func GetVolumePathName(fileName *uint16, volumePathName *uint16, bufferLength ui } func GetVolumePathNamesForVolumeName(volumeName *uint16, volumePathNames *uint16, bufferLength uint32, returnLength *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetVolumePathNamesForVolumeNameW.Addr(), 4, uintptr(unsafe.Pointer(volumeName)), uintptr(unsafe.Pointer(volumePathNames)), uintptr(bufferLength), uintptr(unsafe.Pointer(returnLength)), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetVolumePathNamesForVolumeNameW.Addr(), uintptr(unsafe.Pointer(volumeName)), uintptr(unsafe.Pointer(volumePathNames)), uintptr(bufferLength), uintptr(unsafe.Pointer(returnLength))) if r1 == 0 { err = errnoErr(e1) } @@ -2714,7 +2733,7 @@ func GetVolumePathNamesForVolumeName(volumeName *uint16, volumePathNames *uint16 } func getWindowsDirectory(dir *uint16, dirLen uint32) (len uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetWindowsDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(dirLen), 0) + r0, _, e1 := syscall.SyscallN(procGetWindowsDirectoryW.Addr(), uintptr(unsafe.Pointer(dir)), uintptr(dirLen)) len = uint32(r0) if len == 0 { err = errnoErr(e1) @@ -2723,7 +2742,7 @@ func getWindowsDirectory(dir *uint16, dirLen uint32) (len uint32, err error) { } func initializeProcThreadAttributeList(attrlist *ProcThreadAttributeList, attrcount uint32, flags uint32, size *uintptr) (err error) { - r1, _, e1 := syscall.Syscall6(procInitializeProcThreadAttributeList.Addr(), 4, uintptr(unsafe.Pointer(attrlist)), uintptr(attrcount), uintptr(flags), uintptr(unsafe.Pointer(size)), 0, 0) + r1, _, e1 := syscall.SyscallN(procInitializeProcThreadAttributeList.Addr(), uintptr(unsafe.Pointer(attrlist)), uintptr(attrcount), uintptr(flags), uintptr(unsafe.Pointer(size))) if r1 == 0 { err = errnoErr(e1) } @@ -2735,7 +2754,7 @@ func IsWow64Process(handle Handle, isWow64 *bool) (err error) { if *isWow64 { _p0 = 1 } - r1, _, e1 := syscall.Syscall(procIsWow64Process.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(&_p0)), 0) + r1, _, e1 := syscall.SyscallN(procIsWow64Process.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&_p0))) *isWow64 = _p0 != 0 if r1 == 0 { err = errnoErr(e1) @@ -2748,7 +2767,7 @@ func IsWow64Process2(handle Handle, processMachine *uint16, nativeMachine *uint1 if err != nil { return } - r1, _, e1 := syscall.Syscall(procIsWow64Process2.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(processMachine)), uintptr(unsafe.Pointer(nativeMachine))) + r1, _, e1 := syscall.SyscallN(procIsWow64Process2.Addr(), uintptr(handle), uintptr(unsafe.Pointer(processMachine)), uintptr(unsafe.Pointer(nativeMachine))) if r1 == 0 { err = errnoErr(e1) } @@ -2765,7 +2784,7 @@ func LoadLibraryEx(libname string, zero Handle, flags uintptr) (handle Handle, e } func _LoadLibraryEx(libname *uint16, zero Handle, flags uintptr) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procLoadLibraryExW.Addr(), 3, uintptr(unsafe.Pointer(libname)), uintptr(zero), uintptr(flags)) + r0, _, e1 := syscall.SyscallN(procLoadLibraryExW.Addr(), uintptr(unsafe.Pointer(libname)), uintptr(zero), uintptr(flags)) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -2783,7 +2802,7 @@ func LoadLibrary(libname string) (handle Handle, err error) { } func _LoadLibrary(libname *uint16) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(libname)), 0, 0) + r0, _, e1 := syscall.SyscallN(procLoadLibraryW.Addr(), uintptr(unsafe.Pointer(libname))) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -2792,7 +2811,7 @@ func _LoadLibrary(libname *uint16) (handle Handle, err error) { } func LoadResource(module Handle, resInfo Handle) (resData Handle, err error) { - r0, _, e1 := syscall.Syscall(procLoadResource.Addr(), 2, uintptr(module), uintptr(resInfo), 0) + r0, _, e1 := syscall.SyscallN(procLoadResource.Addr(), uintptr(module), uintptr(resInfo)) resData = Handle(r0) if resData == 0 { err = errnoErr(e1) @@ -2801,7 +2820,7 @@ func LoadResource(module Handle, resInfo Handle) (resData Handle, err error) { } func LocalAlloc(flags uint32, length uint32) (ptr uintptr, err error) { - r0, _, e1 := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(flags), uintptr(length), 0) + r0, _, e1 := syscall.SyscallN(procLocalAlloc.Addr(), uintptr(flags), uintptr(length)) ptr = uintptr(r0) if ptr == 0 { err = errnoErr(e1) @@ -2810,7 +2829,7 @@ func LocalAlloc(flags uint32, length uint32) (ptr uintptr, err error) { } func LocalFree(hmem Handle) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procLocalFree.Addr(), 1, uintptr(hmem), 0, 0) + r0, _, e1 := syscall.SyscallN(procLocalFree.Addr(), uintptr(hmem)) handle = Handle(r0) if handle != 0 { err = errnoErr(e1) @@ -2819,7 +2838,7 @@ func LocalFree(hmem Handle) (handle Handle, err error) { } func LockFileEx(file Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *Overlapped) (err error) { - r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(file), uintptr(flags), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped))) + r1, _, e1 := syscall.SyscallN(procLockFileEx.Addr(), uintptr(file), uintptr(flags), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped))) if r1 == 0 { err = errnoErr(e1) } @@ -2827,7 +2846,7 @@ func LockFileEx(file Handle, flags uint32, reserved uint32, bytesLow uint32, byt } func LockResource(resData Handle) (addr uintptr, err error) { - r0, _, e1 := syscall.Syscall(procLockResource.Addr(), 1, uintptr(resData), 0, 0) + r0, _, e1 := syscall.SyscallN(procLockResource.Addr(), uintptr(resData)) addr = uintptr(r0) if addr == 0 { err = errnoErr(e1) @@ -2836,7 +2855,7 @@ func LockResource(resData Handle) (addr uintptr, err error) { } func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) { - r0, _, e1 := syscall.Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0) + r0, _, e1 := syscall.SyscallN(procMapViewOfFile.Addr(), uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length)) addr = uintptr(r0) if addr == 0 { err = errnoErr(e1) @@ -2845,7 +2864,7 @@ func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow ui } func Module32First(snapshot Handle, moduleEntry *ModuleEntry32) (err error) { - r1, _, e1 := syscall.Syscall(procModule32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry)), 0) + r1, _, e1 := syscall.SyscallN(procModule32FirstW.Addr(), uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry))) if r1 == 0 { err = errnoErr(e1) } @@ -2853,7 +2872,7 @@ func Module32First(snapshot Handle, moduleEntry *ModuleEntry32) (err error) { } func Module32Next(snapshot Handle, moduleEntry *ModuleEntry32) (err error) { - r1, _, e1 := syscall.Syscall(procModule32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry)), 0) + r1, _, e1 := syscall.SyscallN(procModule32NextW.Addr(), uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry))) if r1 == 0 { err = errnoErr(e1) } @@ -2861,7 +2880,7 @@ func Module32Next(snapshot Handle, moduleEntry *ModuleEntry32) (err error) { } func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags)) + r1, _, e1 := syscall.SyscallN(procMoveFileExW.Addr(), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags)) if r1 == 0 { err = errnoErr(e1) } @@ -2869,7 +2888,7 @@ func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) { } func MoveFile(from *uint16, to *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0) + r1, _, e1 := syscall.SyscallN(procMoveFileW.Addr(), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to))) if r1 == 0 { err = errnoErr(e1) } @@ -2877,7 +2896,7 @@ func MoveFile(from *uint16, to *uint16) (err error) { } func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) { - r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar)) + r0, _, e1 := syscall.SyscallN(procMultiByteToWideChar.Addr(), uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar)) nwrite = int32(r0) if nwrite == 0 { err = errnoErr(e1) @@ -2890,7 +2909,7 @@ func OpenEvent(desiredAccess uint32, inheritHandle bool, name *uint16) (handle H if inheritHandle { _p0 = 1 } - r0, _, e1 := syscall.Syscall(procOpenEventW.Addr(), 3, uintptr(desiredAccess), uintptr(_p0), uintptr(unsafe.Pointer(name))) + r0, _, e1 := syscall.SyscallN(procOpenEventW.Addr(), uintptr(desiredAccess), uintptr(_p0), uintptr(unsafe.Pointer(name))) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -2903,7 +2922,7 @@ func OpenMutex(desiredAccess uint32, inheritHandle bool, name *uint16) (handle H if inheritHandle { _p0 = 1 } - r0, _, e1 := syscall.Syscall(procOpenMutexW.Addr(), 3, uintptr(desiredAccess), uintptr(_p0), uintptr(unsafe.Pointer(name))) + r0, _, e1 := syscall.SyscallN(procOpenMutexW.Addr(), uintptr(desiredAccess), uintptr(_p0), uintptr(unsafe.Pointer(name))) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -2916,7 +2935,7 @@ func OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) (ha if inheritHandle { _p0 = 1 } - r0, _, e1 := syscall.Syscall(procOpenProcess.Addr(), 3, uintptr(desiredAccess), uintptr(_p0), uintptr(processId)) + r0, _, e1 := syscall.SyscallN(procOpenProcess.Addr(), uintptr(desiredAccess), uintptr(_p0), uintptr(processId)) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -2929,7 +2948,7 @@ func OpenThread(desiredAccess uint32, inheritHandle bool, threadId uint32) (hand if inheritHandle { _p0 = 1 } - r0, _, e1 := syscall.Syscall(procOpenThread.Addr(), 3, uintptr(desiredAccess), uintptr(_p0), uintptr(threadId)) + r0, _, e1 := syscall.SyscallN(procOpenThread.Addr(), uintptr(desiredAccess), uintptr(_p0), uintptr(threadId)) handle = Handle(r0) if handle == 0 { err = errnoErr(e1) @@ -2938,7 +2957,7 @@ func OpenThread(desiredAccess uint32, inheritHandle bool, threadId uint32) (hand } func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) { - r1, _, e1 := syscall.Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0) + r1, _, e1 := syscall.SyscallN(procPostQueuedCompletionStatus.Addr(), uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped))) if r1 == 0 { err = errnoErr(e1) } @@ -2946,7 +2965,7 @@ func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overla } func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) { - r1, _, e1 := syscall.Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0) + r1, _, e1 := syscall.SyscallN(procProcess32FirstW.Addr(), uintptr(snapshot), uintptr(unsafe.Pointer(procEntry))) if r1 == 0 { err = errnoErr(e1) } @@ -2954,7 +2973,7 @@ func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) { } func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) { - r1, _, e1 := syscall.Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0) + r1, _, e1 := syscall.SyscallN(procProcess32NextW.Addr(), uintptr(snapshot), uintptr(unsafe.Pointer(procEntry))) if r1 == 0 { err = errnoErr(e1) } @@ -2962,7 +2981,7 @@ func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) { } func ProcessIdToSessionId(pid uint32, sessionid *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procProcessIdToSessionId.Addr(), 2, uintptr(pid), uintptr(unsafe.Pointer(sessionid)), 0) + r1, _, e1 := syscall.SyscallN(procProcessIdToSessionId.Addr(), uintptr(pid), uintptr(unsafe.Pointer(sessionid))) if r1 == 0 { err = errnoErr(e1) } @@ -2970,7 +2989,7 @@ func ProcessIdToSessionId(pid uint32, sessionid *uint32) (err error) { } func PulseEvent(event Handle) (err error) { - r1, _, e1 := syscall.Syscall(procPulseEvent.Addr(), 1, uintptr(event), 0, 0) + r1, _, e1 := syscall.SyscallN(procPulseEvent.Addr(), uintptr(event)) if r1 == 0 { err = errnoErr(e1) } @@ -2978,7 +2997,7 @@ func PulseEvent(event Handle) (err error) { } func PurgeComm(handle Handle, dwFlags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procPurgeComm.Addr(), 2, uintptr(handle), uintptr(dwFlags), 0) + r1, _, e1 := syscall.SyscallN(procPurgeComm.Addr(), uintptr(handle), uintptr(dwFlags)) if r1 == 0 { err = errnoErr(e1) } @@ -2986,7 +3005,7 @@ func PurgeComm(handle Handle, dwFlags uint32) (err error) { } func QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procQueryDosDeviceW.Addr(), 3, uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath)), uintptr(max)) + r0, _, e1 := syscall.SyscallN(procQueryDosDeviceW.Addr(), uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath)), uintptr(max)) n = uint32(r0) if n == 0 { err = errnoErr(e1) @@ -2995,7 +3014,7 @@ func QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint3 } func QueryFullProcessImageName(proc Handle, flags uint32, exeName *uint16, size *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procQueryFullProcessImageNameW.Addr(), 4, uintptr(proc), uintptr(flags), uintptr(unsafe.Pointer(exeName)), uintptr(unsafe.Pointer(size)), 0, 0) + r1, _, e1 := syscall.SyscallN(procQueryFullProcessImageNameW.Addr(), uintptr(proc), uintptr(flags), uintptr(unsafe.Pointer(exeName)), uintptr(unsafe.Pointer(size))) if r1 == 0 { err = errnoErr(e1) } @@ -3003,7 +3022,7 @@ func QueryFullProcessImageName(proc Handle, flags uint32, exeName *uint16, size } func QueryInformationJobObject(job Handle, JobObjectInformationClass int32, JobObjectInformation uintptr, JobObjectInformationLength uint32, retlen *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procQueryInformationJobObject.Addr(), 5, uintptr(job), uintptr(JobObjectInformationClass), uintptr(JobObjectInformation), uintptr(JobObjectInformationLength), uintptr(unsafe.Pointer(retlen)), 0) + r1, _, e1 := syscall.SyscallN(procQueryInformationJobObject.Addr(), uintptr(job), uintptr(JobObjectInformationClass), uintptr(JobObjectInformation), uintptr(JobObjectInformationLength), uintptr(unsafe.Pointer(retlen))) if r1 == 0 { err = errnoErr(e1) } @@ -3011,7 +3030,7 @@ func QueryInformationJobObject(job Handle, JobObjectInformationClass int32, JobO } func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) { - r1, _, e1 := syscall.Syscall6(procReadConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(toread), uintptr(unsafe.Pointer(read)), uintptr(unsafe.Pointer(inputControl)), 0) + r1, _, e1 := syscall.SyscallN(procReadConsoleW.Addr(), uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(toread), uintptr(unsafe.Pointer(read)), uintptr(unsafe.Pointer(inputControl))) if r1 == 0 { err = errnoErr(e1) } @@ -3023,7 +3042,7 @@ func ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree if watchSubTree { _p0 = 1 } - r1, _, e1 := syscall.Syscall9(procReadDirectoryChangesW.Addr(), 8, uintptr(handle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(_p0), uintptr(mask), uintptr(unsafe.Pointer(retlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine), 0) + r1, _, e1 := syscall.SyscallN(procReadDirectoryChangesW.Addr(), uintptr(handle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(_p0), uintptr(mask), uintptr(unsafe.Pointer(retlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine)) if r1 == 0 { err = errnoErr(e1) } @@ -3035,7 +3054,7 @@ func readFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) ( if len(buf) > 0 { _p0 = &buf[0] } - r1, _, e1 := syscall.Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) + r1, _, e1 := syscall.SyscallN(procReadFile.Addr(), uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped))) if r1 == 0 { err = errnoErr(e1) } @@ -3043,7 +3062,7 @@ func readFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) ( } func ReadProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size uintptr, numberOfBytesRead *uintptr) (err error) { - r1, _, e1 := syscall.Syscall6(procReadProcessMemory.Addr(), 5, uintptr(process), uintptr(baseAddress), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(numberOfBytesRead)), 0) + r1, _, e1 := syscall.SyscallN(procReadProcessMemory.Addr(), uintptr(process), uintptr(baseAddress), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(numberOfBytesRead))) if r1 == 0 { err = errnoErr(e1) } @@ -3051,7 +3070,7 @@ func ReadProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size u } func ReleaseMutex(mutex Handle) (err error) { - r1, _, e1 := syscall.Syscall(procReleaseMutex.Addr(), 1, uintptr(mutex), 0, 0) + r1, _, e1 := syscall.SyscallN(procReleaseMutex.Addr(), uintptr(mutex)) if r1 == 0 { err = errnoErr(e1) } @@ -3059,7 +3078,7 @@ func ReleaseMutex(mutex Handle) (err error) { } func RemoveDirectory(path *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + r1, _, e1 := syscall.SyscallN(procRemoveDirectoryW.Addr(), uintptr(unsafe.Pointer(path))) if r1 == 0 { err = errnoErr(e1) } @@ -3067,7 +3086,7 @@ func RemoveDirectory(path *uint16) (err error) { } func RemoveDllDirectory(cookie uintptr) (err error) { - r1, _, e1 := syscall.Syscall(procRemoveDllDirectory.Addr(), 1, uintptr(cookie), 0, 0) + r1, _, e1 := syscall.SyscallN(procRemoveDllDirectory.Addr(), uintptr(cookie)) if r1 == 0 { err = errnoErr(e1) } @@ -3075,7 +3094,7 @@ func RemoveDllDirectory(cookie uintptr) (err error) { } func ResetEvent(event Handle) (err error) { - r1, _, e1 := syscall.Syscall(procResetEvent.Addr(), 1, uintptr(event), 0, 0) + r1, _, e1 := syscall.SyscallN(procResetEvent.Addr(), uintptr(event)) if r1 == 0 { err = errnoErr(e1) } @@ -3083,7 +3102,7 @@ func ResetEvent(event Handle) (err error) { } func resizePseudoConsole(pconsole Handle, size uint32) (hr error) { - r0, _, _ := syscall.Syscall(procResizePseudoConsole.Addr(), 2, uintptr(pconsole), uintptr(size), 0) + r0, _, _ := syscall.SyscallN(procResizePseudoConsole.Addr(), uintptr(pconsole), uintptr(size)) if r0 != 0 { hr = syscall.Errno(r0) } @@ -3091,7 +3110,7 @@ func resizePseudoConsole(pconsole Handle, size uint32) (hr error) { } func ResumeThread(thread Handle) (ret uint32, err error) { - r0, _, e1 := syscall.Syscall(procResumeThread.Addr(), 1, uintptr(thread), 0, 0) + r0, _, e1 := syscall.SyscallN(procResumeThread.Addr(), uintptr(thread)) ret = uint32(r0) if ret == 0xffffffff { err = errnoErr(e1) @@ -3100,7 +3119,7 @@ func ResumeThread(thread Handle) (ret uint32, err error) { } func SetCommBreak(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procSetCommBreak.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetCommBreak.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -3108,7 +3127,7 @@ func SetCommBreak(handle Handle) (err error) { } func SetCommMask(handle Handle, dwEvtMask uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetCommMask.Addr(), 2, uintptr(handle), uintptr(dwEvtMask), 0) + r1, _, e1 := syscall.SyscallN(procSetCommMask.Addr(), uintptr(handle), uintptr(dwEvtMask)) if r1 == 0 { err = errnoErr(e1) } @@ -3116,7 +3135,7 @@ func SetCommMask(handle Handle, dwEvtMask uint32) (err error) { } func SetCommState(handle Handle, lpDCB *DCB) (err error) { - r1, _, e1 := syscall.Syscall(procSetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpDCB)), 0) + r1, _, e1 := syscall.SyscallN(procSetCommState.Addr(), uintptr(handle), uintptr(unsafe.Pointer(lpDCB))) if r1 == 0 { err = errnoErr(e1) } @@ -3124,7 +3143,7 @@ func SetCommState(handle Handle, lpDCB *DCB) (err error) { } func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { - r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) + r1, _, e1 := syscall.SyscallN(procSetCommTimeouts.Addr(), uintptr(handle), uintptr(unsafe.Pointer(timeouts))) if r1 == 0 { err = errnoErr(e1) } @@ -3132,7 +3151,7 @@ func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { } func SetConsoleCP(cp uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetConsoleCP.Addr(), 1, uintptr(cp), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetConsoleCP.Addr(), uintptr(cp)) if r1 == 0 { err = errnoErr(e1) } @@ -3140,7 +3159,7 @@ func SetConsoleCP(cp uint32) (err error) { } func setConsoleCursorPosition(console Handle, position uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetConsoleCursorPosition.Addr(), 2, uintptr(console), uintptr(position), 0) + r1, _, e1 := syscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(console), uintptr(position)) if r1 == 0 { err = errnoErr(e1) } @@ -3148,7 +3167,7 @@ func setConsoleCursorPosition(console Handle, position uint32) (err error) { } func SetConsoleMode(console Handle, mode uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(console), uintptr(mode), 0) + r1, _, e1 := syscall.SyscallN(procSetConsoleMode.Addr(), uintptr(console), uintptr(mode)) if r1 == 0 { err = errnoErr(e1) } @@ -3156,7 +3175,7 @@ func SetConsoleMode(console Handle, mode uint32) (err error) { } func SetConsoleOutputCP(cp uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetConsoleOutputCP.Addr(), 1, uintptr(cp), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetConsoleOutputCP.Addr(), uintptr(cp)) if r1 == 0 { err = errnoErr(e1) } @@ -3164,7 +3183,7 @@ func SetConsoleOutputCP(cp uint32) (err error) { } func SetCurrentDirectory(path *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetCurrentDirectoryW.Addr(), uintptr(unsafe.Pointer(path))) if r1 == 0 { err = errnoErr(e1) } @@ -3172,7 +3191,7 @@ func SetCurrentDirectory(path *uint16) (err error) { } func SetDefaultDllDirectories(directoryFlags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetDefaultDllDirectories.Addr(), 1, uintptr(directoryFlags), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetDefaultDllDirectories.Addr(), uintptr(directoryFlags)) if r1 == 0 { err = errnoErr(e1) } @@ -3189,7 +3208,7 @@ func SetDllDirectory(path string) (err error) { } func _SetDllDirectory(path *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procSetDllDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetDllDirectoryW.Addr(), uintptr(unsafe.Pointer(path))) if r1 == 0 { err = errnoErr(e1) } @@ -3197,7 +3216,7 @@ func _SetDllDirectory(path *uint16) (err error) { } func SetEndOfFile(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetEndOfFile.Addr(), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -3205,7 +3224,7 @@ func SetEndOfFile(handle Handle) (err error) { } func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) + r1, _, e1 := syscall.SyscallN(procSetEnvironmentVariableW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value))) if r1 == 0 { err = errnoErr(e1) } @@ -3213,13 +3232,13 @@ func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { } func SetErrorMode(mode uint32) (ret uint32) { - r0, _, _ := syscall.Syscall(procSetErrorMode.Addr(), 1, uintptr(mode), 0, 0) + r0, _, _ := syscall.SyscallN(procSetErrorMode.Addr(), uintptr(mode)) ret = uint32(r0) return } func SetEvent(event Handle) (err error) { - r1, _, e1 := syscall.Syscall(procSetEvent.Addr(), 1, uintptr(event), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetEvent.Addr(), uintptr(event)) if r1 == 0 { err = errnoErr(e1) } @@ -3227,7 +3246,7 @@ func SetEvent(event Handle) (err error) { } func SetFileAttributes(name *uint16, attrs uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0) + r1, _, e1 := syscall.SyscallN(procSetFileAttributesW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(attrs)) if r1 == 0 { err = errnoErr(e1) } @@ -3235,7 +3254,7 @@ func SetFileAttributes(name *uint16, attrs uint32) (err error) { } func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) { - r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(handle), uintptr(flags), 0) + r1, _, e1 := syscall.SyscallN(procSetFileCompletionNotificationModes.Addr(), uintptr(handle), uintptr(flags)) if r1 == 0 { err = errnoErr(e1) } @@ -3243,7 +3262,7 @@ func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) } func SetFileInformationByHandle(handle Handle, class uint32, inBuffer *byte, inBufferLen uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(handle), uintptr(class), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferLen), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetFileInformationByHandle.Addr(), uintptr(handle), uintptr(class), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferLen)) if r1 == 0 { err = errnoErr(e1) } @@ -3251,7 +3270,7 @@ func SetFileInformationByHandle(handle Handle, class uint32, inBuffer *byte, inB } func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) { - r0, _, e1 := syscall.Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0) + r0, _, e1 := syscall.SyscallN(procSetFilePointer.Addr(), uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence)) newlowoffset = uint32(r0) if newlowoffset == 0xffffffff { err = errnoErr(e1) @@ -3260,7 +3279,7 @@ func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence } func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) { - r1, _, e1 := syscall.Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetFileTime.Addr(), uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime))) if r1 == 0 { err = errnoErr(e1) } @@ -3268,7 +3287,7 @@ func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetim } func SetFileValidData(handle Handle, validDataLength int64) (err error) { - r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0) + r1, _, e1 := syscall.SyscallN(procSetFileValidData.Addr(), uintptr(handle), uintptr(validDataLength)) if r1 == 0 { err = errnoErr(e1) } @@ -3276,7 +3295,7 @@ func SetFileValidData(handle Handle, validDataLength int64) (err error) { } func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags)) + r1, _, e1 := syscall.SyscallN(procSetHandleInformation.Addr(), uintptr(handle), uintptr(mask), uintptr(flags)) if r1 == 0 { err = errnoErr(e1) } @@ -3284,7 +3303,7 @@ func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) } func SetInformationJobObject(job Handle, JobObjectInformationClass uint32, JobObjectInformation uintptr, JobObjectInformationLength uint32) (ret int, err error) { - r0, _, e1 := syscall.Syscall6(procSetInformationJobObject.Addr(), 4, uintptr(job), uintptr(JobObjectInformationClass), uintptr(JobObjectInformation), uintptr(JobObjectInformationLength), 0, 0) + r0, _, e1 := syscall.SyscallN(procSetInformationJobObject.Addr(), uintptr(job), uintptr(JobObjectInformationClass), uintptr(JobObjectInformation), uintptr(JobObjectInformationLength)) ret = int(r0) if ret == 0 { err = errnoErr(e1) @@ -3293,7 +3312,7 @@ func SetInformationJobObject(job Handle, JobObjectInformationClass uint32, JobOb } func SetNamedPipeHandleState(pipe Handle, state *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetNamedPipeHandleState.Addr(), 4, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetNamedPipeHandleState.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout))) if r1 == 0 { err = errnoErr(e1) } @@ -3301,7 +3320,7 @@ func SetNamedPipeHandleState(pipe Handle, state *uint32, maxCollectionCount *uin } func SetPriorityClass(process Handle, priorityClass uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetPriorityClass.Addr(), 2, uintptr(process), uintptr(priorityClass), 0) + r1, _, e1 := syscall.SyscallN(procSetPriorityClass.Addr(), uintptr(process), uintptr(priorityClass)) if r1 == 0 { err = errnoErr(e1) } @@ -3313,7 +3332,7 @@ func SetProcessPriorityBoost(process Handle, disable bool) (err error) { if disable { _p0 = 1 } - r1, _, e1 := syscall.Syscall(procSetProcessPriorityBoost.Addr(), 2, uintptr(process), uintptr(_p0), 0) + r1, _, e1 := syscall.SyscallN(procSetProcessPriorityBoost.Addr(), uintptr(process), uintptr(_p0)) if r1 == 0 { err = errnoErr(e1) } @@ -3321,7 +3340,7 @@ func SetProcessPriorityBoost(process Handle, disable bool) (err error) { } func SetProcessShutdownParameters(level uint32, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetProcessShutdownParameters.Addr(), 2, uintptr(level), uintptr(flags), 0) + r1, _, e1 := syscall.SyscallN(procSetProcessShutdownParameters.Addr(), uintptr(level), uintptr(flags)) if r1 == 0 { err = errnoErr(e1) } @@ -3329,7 +3348,7 @@ func SetProcessShutdownParameters(level uint32, flags uint32) (err error) { } func SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetProcessWorkingSetSizeEx.Addr(), 4, uintptr(hProcess), uintptr(dwMinimumWorkingSetSize), uintptr(dwMaximumWorkingSetSize), uintptr(flags), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetProcessWorkingSetSizeEx.Addr(), uintptr(hProcess), uintptr(dwMinimumWorkingSetSize), uintptr(dwMaximumWorkingSetSize), uintptr(flags)) if r1 == 0 { err = errnoErr(e1) } @@ -3337,7 +3356,7 @@ func SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr } func SetStdHandle(stdhandle uint32, handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procSetStdHandle.Addr(), 2, uintptr(stdhandle), uintptr(handle), 0) + r1, _, e1 := syscall.SyscallN(procSetStdHandle.Addr(), uintptr(stdhandle), uintptr(handle)) if r1 == 0 { err = errnoErr(e1) } @@ -3345,7 +3364,7 @@ func SetStdHandle(stdhandle uint32, handle Handle) (err error) { } func SetVolumeLabel(rootPathName *uint16, volumeName *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procSetVolumeLabelW.Addr(), 2, uintptr(unsafe.Pointer(rootPathName)), uintptr(unsafe.Pointer(volumeName)), 0) + r1, _, e1 := syscall.SyscallN(procSetVolumeLabelW.Addr(), uintptr(unsafe.Pointer(rootPathName)), uintptr(unsafe.Pointer(volumeName))) if r1 == 0 { err = errnoErr(e1) } @@ -3353,7 +3372,7 @@ func SetVolumeLabel(rootPathName *uint16, volumeName *uint16) (err error) { } func SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procSetVolumeMountPointW.Addr(), 2, uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(unsafe.Pointer(volumeName)), 0) + r1, _, e1 := syscall.SyscallN(procSetVolumeMountPointW.Addr(), uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(unsafe.Pointer(volumeName))) if r1 == 0 { err = errnoErr(e1) } @@ -3361,7 +3380,7 @@ func SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err erro } func SetupComm(handle Handle, dwInQueue uint32, dwOutQueue uint32) (err error) { - r1, _, e1 := syscall.Syscall(procSetupComm.Addr(), 3, uintptr(handle), uintptr(dwInQueue), uintptr(dwOutQueue)) + r1, _, e1 := syscall.SyscallN(procSetupComm.Addr(), uintptr(handle), uintptr(dwInQueue), uintptr(dwOutQueue)) if r1 == 0 { err = errnoErr(e1) } @@ -3369,7 +3388,7 @@ func SetupComm(handle Handle, dwInQueue uint32, dwOutQueue uint32) (err error) { } func SizeofResource(module Handle, resInfo Handle) (size uint32, err error) { - r0, _, e1 := syscall.Syscall(procSizeofResource.Addr(), 2, uintptr(module), uintptr(resInfo), 0) + r0, _, e1 := syscall.SyscallN(procSizeofResource.Addr(), uintptr(module), uintptr(resInfo)) size = uint32(r0) if size == 0 { err = errnoErr(e1) @@ -3382,13 +3401,13 @@ func SleepEx(milliseconds uint32, alertable bool) (ret uint32) { if alertable { _p0 = 1 } - r0, _, _ := syscall.Syscall(procSleepEx.Addr(), 2, uintptr(milliseconds), uintptr(_p0), 0) + r0, _, _ := syscall.SyscallN(procSleepEx.Addr(), uintptr(milliseconds), uintptr(_p0)) ret = uint32(r0) return } func TerminateJobObject(job Handle, exitCode uint32) (err error) { - r1, _, e1 := syscall.Syscall(procTerminateJobObject.Addr(), 2, uintptr(job), uintptr(exitCode), 0) + r1, _, e1 := syscall.SyscallN(procTerminateJobObject.Addr(), uintptr(job), uintptr(exitCode)) if r1 == 0 { err = errnoErr(e1) } @@ -3396,7 +3415,7 @@ func TerminateJobObject(job Handle, exitCode uint32) (err error) { } func TerminateProcess(handle Handle, exitcode uint32) (err error) { - r1, _, e1 := syscall.Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0) + r1, _, e1 := syscall.SyscallN(procTerminateProcess.Addr(), uintptr(handle), uintptr(exitcode)) if r1 == 0 { err = errnoErr(e1) } @@ -3404,7 +3423,7 @@ func TerminateProcess(handle Handle, exitcode uint32) (err error) { } func Thread32First(snapshot Handle, threadEntry *ThreadEntry32) (err error) { - r1, _, e1 := syscall.Syscall(procThread32First.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(threadEntry)), 0) + r1, _, e1 := syscall.SyscallN(procThread32First.Addr(), uintptr(snapshot), uintptr(unsafe.Pointer(threadEntry))) if r1 == 0 { err = errnoErr(e1) } @@ -3412,7 +3431,7 @@ func Thread32First(snapshot Handle, threadEntry *ThreadEntry32) (err error) { } func Thread32Next(snapshot Handle, threadEntry *ThreadEntry32) (err error) { - r1, _, e1 := syscall.Syscall(procThread32Next.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(threadEntry)), 0) + r1, _, e1 := syscall.SyscallN(procThread32Next.Addr(), uintptr(snapshot), uintptr(unsafe.Pointer(threadEntry))) if r1 == 0 { err = errnoErr(e1) } @@ -3420,7 +3439,7 @@ func Thread32Next(snapshot Handle, threadEntry *ThreadEntry32) (err error) { } func UnlockFileEx(file Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *Overlapped) (err error) { - r1, _, e1 := syscall.Syscall6(procUnlockFileEx.Addr(), 5, uintptr(file), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped)), 0) + r1, _, e1 := syscall.SyscallN(procUnlockFileEx.Addr(), uintptr(file), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped))) if r1 == 0 { err = errnoErr(e1) } @@ -3428,7 +3447,7 @@ func UnlockFileEx(file Handle, reserved uint32, bytesLow uint32, bytesHigh uint3 } func UnmapViewOfFile(addr uintptr) (err error) { - r1, _, e1 := syscall.Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0) + r1, _, e1 := syscall.SyscallN(procUnmapViewOfFile.Addr(), uintptr(addr)) if r1 == 0 { err = errnoErr(e1) } @@ -3436,7 +3455,7 @@ func UnmapViewOfFile(addr uintptr) (err error) { } func updateProcThreadAttribute(attrlist *ProcThreadAttributeList, flags uint32, attr uintptr, value unsafe.Pointer, size uintptr, prevvalue unsafe.Pointer, returnedsize *uintptr) (err error) { - r1, _, e1 := syscall.Syscall9(procUpdateProcThreadAttribute.Addr(), 7, uintptr(unsafe.Pointer(attrlist)), uintptr(flags), uintptr(attr), uintptr(value), uintptr(size), uintptr(prevvalue), uintptr(unsafe.Pointer(returnedsize)), 0, 0) + r1, _, e1 := syscall.SyscallN(procUpdateProcThreadAttribute.Addr(), uintptr(unsafe.Pointer(attrlist)), uintptr(flags), uintptr(attr), uintptr(value), uintptr(size), uintptr(prevvalue), uintptr(unsafe.Pointer(returnedsize))) if r1 == 0 { err = errnoErr(e1) } @@ -3444,7 +3463,7 @@ func updateProcThreadAttribute(attrlist *ProcThreadAttributeList, flags uint32, } func VirtualAlloc(address uintptr, size uintptr, alloctype uint32, protect uint32) (value uintptr, err error) { - r0, _, e1 := syscall.Syscall6(procVirtualAlloc.Addr(), 4, uintptr(address), uintptr(size), uintptr(alloctype), uintptr(protect), 0, 0) + r0, _, e1 := syscall.SyscallN(procVirtualAlloc.Addr(), uintptr(address), uintptr(size), uintptr(alloctype), uintptr(protect)) value = uintptr(r0) if value == 0 { err = errnoErr(e1) @@ -3453,7 +3472,7 @@ func VirtualAlloc(address uintptr, size uintptr, alloctype uint32, protect uint3 } func VirtualFree(address uintptr, size uintptr, freetype uint32) (err error) { - r1, _, e1 := syscall.Syscall(procVirtualFree.Addr(), 3, uintptr(address), uintptr(size), uintptr(freetype)) + r1, _, e1 := syscall.SyscallN(procVirtualFree.Addr(), uintptr(address), uintptr(size), uintptr(freetype)) if r1 == 0 { err = errnoErr(e1) } @@ -3461,7 +3480,7 @@ func VirtualFree(address uintptr, size uintptr, freetype uint32) (err error) { } func VirtualLock(addr uintptr, length uintptr) (err error) { - r1, _, e1 := syscall.Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0) + r1, _, e1 := syscall.SyscallN(procVirtualLock.Addr(), uintptr(addr), uintptr(length)) if r1 == 0 { err = errnoErr(e1) } @@ -3469,7 +3488,7 @@ func VirtualLock(addr uintptr, length uintptr) (err error) { } func VirtualProtect(address uintptr, size uintptr, newprotect uint32, oldprotect *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procVirtualProtect.Addr(), 4, uintptr(address), uintptr(size), uintptr(newprotect), uintptr(unsafe.Pointer(oldprotect)), 0, 0) + r1, _, e1 := syscall.SyscallN(procVirtualProtect.Addr(), uintptr(address), uintptr(size), uintptr(newprotect), uintptr(unsafe.Pointer(oldprotect))) if r1 == 0 { err = errnoErr(e1) } @@ -3477,7 +3496,7 @@ func VirtualProtect(address uintptr, size uintptr, newprotect uint32, oldprotect } func VirtualProtectEx(process Handle, address uintptr, size uintptr, newProtect uint32, oldProtect *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procVirtualProtectEx.Addr(), 5, uintptr(process), uintptr(address), uintptr(size), uintptr(newProtect), uintptr(unsafe.Pointer(oldProtect)), 0) + r1, _, e1 := syscall.SyscallN(procVirtualProtectEx.Addr(), uintptr(process), uintptr(address), uintptr(size), uintptr(newProtect), uintptr(unsafe.Pointer(oldProtect))) if r1 == 0 { err = errnoErr(e1) } @@ -3485,7 +3504,7 @@ func VirtualProtectEx(process Handle, address uintptr, size uintptr, newProtect } func VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) { - r1, _, e1 := syscall.Syscall(procVirtualQuery.Addr(), 3, uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length)) + r1, _, e1 := syscall.SyscallN(procVirtualQuery.Addr(), uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length)) if r1 == 0 { err = errnoErr(e1) } @@ -3493,7 +3512,7 @@ func VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintpt } func VirtualQueryEx(process Handle, address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) { - r1, _, e1 := syscall.Syscall6(procVirtualQueryEx.Addr(), 4, uintptr(process), uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length), 0, 0) + r1, _, e1 := syscall.SyscallN(procVirtualQueryEx.Addr(), uintptr(process), uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length)) if r1 == 0 { err = errnoErr(e1) } @@ -3501,7 +3520,7 @@ func VirtualQueryEx(process Handle, address uintptr, buffer *MemoryBasicInformat } func VirtualUnlock(addr uintptr, length uintptr) (err error) { - r1, _, e1 := syscall.Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0) + r1, _, e1 := syscall.SyscallN(procVirtualUnlock.Addr(), uintptr(addr), uintptr(length)) if r1 == 0 { err = errnoErr(e1) } @@ -3509,13 +3528,13 @@ func VirtualUnlock(addr uintptr, length uintptr) (err error) { } func WTSGetActiveConsoleSessionId() (sessionID uint32) { - r0, _, _ := syscall.Syscall(procWTSGetActiveConsoleSessionId.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procWTSGetActiveConsoleSessionId.Addr()) sessionID = uint32(r0) return } func WaitCommEvent(handle Handle, lpEvtMask *uint32, lpOverlapped *Overlapped) (err error) { - r1, _, e1 := syscall.Syscall(procWaitCommEvent.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(lpEvtMask)), uintptr(unsafe.Pointer(lpOverlapped))) + r1, _, e1 := syscall.SyscallN(procWaitCommEvent.Addr(), uintptr(handle), uintptr(unsafe.Pointer(lpEvtMask)), uintptr(unsafe.Pointer(lpOverlapped))) if r1 == 0 { err = errnoErr(e1) } @@ -3527,7 +3546,7 @@ func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMil if waitAll { _p0 = 1 } - r0, _, e1 := syscall.Syscall6(procWaitForMultipleObjects.Addr(), 4, uintptr(count), uintptr(handles), uintptr(_p0), uintptr(waitMilliseconds), 0, 0) + r0, _, e1 := syscall.SyscallN(procWaitForMultipleObjects.Addr(), uintptr(count), uintptr(handles), uintptr(_p0), uintptr(waitMilliseconds)) event = uint32(r0) if event == 0xffffffff { err = errnoErr(e1) @@ -3536,7 +3555,7 @@ func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMil } func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) { - r0, _, e1 := syscall.Syscall(procWaitForSingleObject.Addr(), 2, uintptr(handle), uintptr(waitMilliseconds), 0) + r0, _, e1 := syscall.SyscallN(procWaitForSingleObject.Addr(), uintptr(handle), uintptr(waitMilliseconds)) event = uint32(r0) if event == 0xffffffff { err = errnoErr(e1) @@ -3545,7 +3564,7 @@ func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, } func WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) { - r1, _, e1 := syscall.Syscall6(procWriteConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(towrite), uintptr(unsafe.Pointer(written)), uintptr(unsafe.Pointer(reserved)), 0) + r1, _, e1 := syscall.SyscallN(procWriteConsoleW.Addr(), uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(towrite), uintptr(unsafe.Pointer(written)), uintptr(unsafe.Pointer(reserved))) if r1 == 0 { err = errnoErr(e1) } @@ -3557,7 +3576,7 @@ func writeFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) if len(buf) > 0 { _p0 = &buf[0] } - r1, _, e1 := syscall.Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) + r1, _, e1 := syscall.SyscallN(procWriteFile.Addr(), uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped))) if r1 == 0 { err = errnoErr(e1) } @@ -3565,7 +3584,7 @@ func writeFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) } func WriteProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size uintptr, numberOfBytesWritten *uintptr) (err error) { - r1, _, e1 := syscall.Syscall6(procWriteProcessMemory.Addr(), 5, uintptr(process), uintptr(baseAddress), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(numberOfBytesWritten)), 0) + r1, _, e1 := syscall.SyscallN(procWriteProcessMemory.Addr(), uintptr(process), uintptr(baseAddress), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(numberOfBytesWritten))) if r1 == 0 { err = errnoErr(e1) } @@ -3573,7 +3592,7 @@ func WriteProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size } func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) { - r1, _, e1 := syscall.Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0) + r1, _, e1 := syscall.SyscallN(procAcceptEx.Addr(), uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped))) if r1 == 0 { err = errnoErr(e1) } @@ -3581,12 +3600,12 @@ func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32 } func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) { - syscall.Syscall9(procGetAcceptExSockaddrs.Addr(), 8, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0) + syscall.SyscallN(procGetAcceptExSockaddrs.Addr(), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen))) return } func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0) + r1, _, e1 := syscall.SyscallN(procTransmitFile.Addr(), uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags)) if r1 == 0 { err = errnoErr(e1) } @@ -3594,7 +3613,7 @@ func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint } func NetApiBufferFree(buf *byte) (neterr error) { - r0, _, _ := syscall.Syscall(procNetApiBufferFree.Addr(), 1, uintptr(unsafe.Pointer(buf)), 0, 0) + r0, _, _ := syscall.SyscallN(procNetApiBufferFree.Addr(), uintptr(unsafe.Pointer(buf))) if r0 != 0 { neterr = syscall.Errno(r0) } @@ -3602,7 +3621,7 @@ func NetApiBufferFree(buf *byte) (neterr error) { } func NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) { - r0, _, _ := syscall.Syscall(procNetGetJoinInformation.Addr(), 3, uintptr(unsafe.Pointer(server)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(bufType))) + r0, _, _ := syscall.SyscallN(procNetGetJoinInformation.Addr(), uintptr(unsafe.Pointer(server)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(bufType))) if r0 != 0 { neterr = syscall.Errno(r0) } @@ -3610,7 +3629,7 @@ func NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (nete } func NetUserEnum(serverName *uint16, level uint32, filter uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32, resumeHandle *uint32) (neterr error) { - r0, _, _ := syscall.Syscall9(procNetUserEnum.Addr(), 8, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(filter), uintptr(unsafe.Pointer(buf)), uintptr(prefMaxLen), uintptr(unsafe.Pointer(entriesRead)), uintptr(unsafe.Pointer(totalEntries)), uintptr(unsafe.Pointer(resumeHandle)), 0) + r0, _, _ := syscall.SyscallN(procNetUserEnum.Addr(), uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(filter), uintptr(unsafe.Pointer(buf)), uintptr(prefMaxLen), uintptr(unsafe.Pointer(entriesRead)), uintptr(unsafe.Pointer(totalEntries)), uintptr(unsafe.Pointer(resumeHandle))) if r0 != 0 { neterr = syscall.Errno(r0) } @@ -3618,7 +3637,7 @@ func NetUserEnum(serverName *uint16, level uint32, filter uint32, buf **byte, pr } func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) { - r0, _, _ := syscall.Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0) + r0, _, _ := syscall.SyscallN(procNetUserGetInfo.Addr(), uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf))) if r0 != 0 { neterr = syscall.Errno(r0) } @@ -3626,7 +3645,7 @@ func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **by } func NtCreateFile(handle *Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, allocationSize *int64, attributes uint32, share uint32, disposition uint32, options uint32, eabuffer uintptr, ealength uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall12(procNtCreateFile.Addr(), 11, uintptr(unsafe.Pointer(handle)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(allocationSize)), uintptr(attributes), uintptr(share), uintptr(disposition), uintptr(options), uintptr(eabuffer), uintptr(ealength), 0) + r0, _, _ := syscall.SyscallN(procNtCreateFile.Addr(), uintptr(unsafe.Pointer(handle)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(allocationSize)), uintptr(attributes), uintptr(share), uintptr(disposition), uintptr(options), uintptr(eabuffer), uintptr(ealength)) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3634,7 +3653,7 @@ func NtCreateFile(handle *Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO } func NtCreateNamedPipeFile(pipe *Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (ntstatus error) { - r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0) + r0, _, _ := syscall.SyscallN(procNtCreateNamedPipeFile.Addr(), uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout))) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3642,7 +3661,7 @@ func NtCreateNamedPipeFile(pipe *Handle, access uint32, oa *OBJECT_ATTRIBUTES, i } func NtQueryInformationProcess(proc Handle, procInfoClass int32, procInfo unsafe.Pointer, procInfoLen uint32, retLen *uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall6(procNtQueryInformationProcess.Addr(), 5, uintptr(proc), uintptr(procInfoClass), uintptr(procInfo), uintptr(procInfoLen), uintptr(unsafe.Pointer(retLen)), 0) + r0, _, _ := syscall.SyscallN(procNtQueryInformationProcess.Addr(), uintptr(proc), uintptr(procInfoClass), uintptr(procInfo), uintptr(procInfoLen), uintptr(unsafe.Pointer(retLen))) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3650,7 +3669,7 @@ func NtQueryInformationProcess(proc Handle, procInfoClass int32, procInfo unsafe } func NtQuerySystemInformation(sysInfoClass int32, sysInfo unsafe.Pointer, sysInfoLen uint32, retLen *uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall6(procNtQuerySystemInformation.Addr(), 4, uintptr(sysInfoClass), uintptr(sysInfo), uintptr(sysInfoLen), uintptr(unsafe.Pointer(retLen)), 0, 0) + r0, _, _ := syscall.SyscallN(procNtQuerySystemInformation.Addr(), uintptr(sysInfoClass), uintptr(sysInfo), uintptr(sysInfoLen), uintptr(unsafe.Pointer(retLen))) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3658,7 +3677,7 @@ func NtQuerySystemInformation(sysInfoClass int32, sysInfo unsafe.Pointer, sysInf } func NtSetInformationFile(handle Handle, iosb *IO_STATUS_BLOCK, inBuffer *byte, inBufferLen uint32, class uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferLen), uintptr(class), 0) + r0, _, _ := syscall.SyscallN(procNtSetInformationFile.Addr(), uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferLen), uintptr(class)) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3666,7 +3685,7 @@ func NtSetInformationFile(handle Handle, iosb *IO_STATUS_BLOCK, inBuffer *byte, } func NtSetInformationProcess(proc Handle, procInfoClass int32, procInfo unsafe.Pointer, procInfoLen uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall6(procNtSetInformationProcess.Addr(), 4, uintptr(proc), uintptr(procInfoClass), uintptr(procInfo), uintptr(procInfoLen), 0, 0) + r0, _, _ := syscall.SyscallN(procNtSetInformationProcess.Addr(), uintptr(proc), uintptr(procInfoClass), uintptr(procInfo), uintptr(procInfoLen)) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3674,7 +3693,7 @@ func NtSetInformationProcess(proc Handle, procInfoClass int32, procInfo unsafe.P } func NtSetSystemInformation(sysInfoClass int32, sysInfo unsafe.Pointer, sysInfoLen uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall(procNtSetSystemInformation.Addr(), 3, uintptr(sysInfoClass), uintptr(sysInfo), uintptr(sysInfoLen)) + r0, _, _ := syscall.SyscallN(procNtSetSystemInformation.Addr(), uintptr(sysInfoClass), uintptr(sysInfo), uintptr(sysInfoLen)) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3682,13 +3701,13 @@ func NtSetSystemInformation(sysInfoClass int32, sysInfo unsafe.Pointer, sysInfoL } func RtlAddFunctionTable(functionTable *RUNTIME_FUNCTION, entryCount uint32, baseAddress uintptr) (ret bool) { - r0, _, _ := syscall.Syscall(procRtlAddFunctionTable.Addr(), 3, uintptr(unsafe.Pointer(functionTable)), uintptr(entryCount), uintptr(baseAddress)) + r0, _, _ := syscall.SyscallN(procRtlAddFunctionTable.Addr(), uintptr(unsafe.Pointer(functionTable)), uintptr(entryCount), uintptr(baseAddress)) ret = r0 != 0 return } func RtlDefaultNpAcl(acl **ACL) (ntstatus error) { - r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(acl)), 0, 0) + r0, _, _ := syscall.SyscallN(procRtlDefaultNpAcl.Addr(), uintptr(unsafe.Pointer(acl))) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3696,13 +3715,13 @@ func RtlDefaultNpAcl(acl **ACL) (ntstatus error) { } func RtlDeleteFunctionTable(functionTable *RUNTIME_FUNCTION) (ret bool) { - r0, _, _ := syscall.Syscall(procRtlDeleteFunctionTable.Addr(), 1, uintptr(unsafe.Pointer(functionTable)), 0, 0) + r0, _, _ := syscall.SyscallN(procRtlDeleteFunctionTable.Addr(), uintptr(unsafe.Pointer(functionTable))) ret = r0 != 0 return } func RtlDosPathNameToNtPathName(dosName *uint16, ntName *NTUnicodeString, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) { - r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U_WithStatus.Addr(), 4, uintptr(unsafe.Pointer(dosName)), uintptr(unsafe.Pointer(ntName)), uintptr(unsafe.Pointer(ntFileNamePart)), uintptr(unsafe.Pointer(relativeName)), 0, 0) + r0, _, _ := syscall.SyscallN(procRtlDosPathNameToNtPathName_U_WithStatus.Addr(), uintptr(unsafe.Pointer(dosName)), uintptr(unsafe.Pointer(ntName)), uintptr(unsafe.Pointer(ntFileNamePart)), uintptr(unsafe.Pointer(relativeName))) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3710,7 +3729,7 @@ func RtlDosPathNameToNtPathName(dosName *uint16, ntName *NTUnicodeString, ntFile } func RtlDosPathNameToRelativeNtPathName(dosName *uint16, ntName *NTUnicodeString, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) { - r0, _, _ := syscall.Syscall6(procRtlDosPathNameToRelativeNtPathName_U_WithStatus.Addr(), 4, uintptr(unsafe.Pointer(dosName)), uintptr(unsafe.Pointer(ntName)), uintptr(unsafe.Pointer(ntFileNamePart)), uintptr(unsafe.Pointer(relativeName)), 0, 0) + r0, _, _ := syscall.SyscallN(procRtlDosPathNameToRelativeNtPathName_U_WithStatus.Addr(), uintptr(unsafe.Pointer(dosName)), uintptr(unsafe.Pointer(ntName)), uintptr(unsafe.Pointer(ntFileNamePart)), uintptr(unsafe.Pointer(relativeName))) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3718,18 +3737,18 @@ func RtlDosPathNameToRelativeNtPathName(dosName *uint16, ntName *NTUnicodeString } func RtlGetCurrentPeb() (peb *PEB) { - r0, _, _ := syscall.Syscall(procRtlGetCurrentPeb.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procRtlGetCurrentPeb.Addr()) peb = (*PEB)(unsafe.Pointer(r0)) return } func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) { - syscall.Syscall(procRtlGetNtVersionNumbers.Addr(), 3, uintptr(unsafe.Pointer(majorVersion)), uintptr(unsafe.Pointer(minorVersion)), uintptr(unsafe.Pointer(buildNumber))) + syscall.SyscallN(procRtlGetNtVersionNumbers.Addr(), uintptr(unsafe.Pointer(majorVersion)), uintptr(unsafe.Pointer(minorVersion)), uintptr(unsafe.Pointer(buildNumber))) return } func rtlGetVersion(info *OsVersionInfoEx) (ntstatus error) { - r0, _, _ := syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0) + r0, _, _ := syscall.SyscallN(procRtlGetVersion.Addr(), uintptr(unsafe.Pointer(info))) if r0 != 0 { ntstatus = NTStatus(r0) } @@ -3737,23 +3756,23 @@ func rtlGetVersion(info *OsVersionInfoEx) (ntstatus error) { } func RtlInitString(destinationString *NTString, sourceString *byte) { - syscall.Syscall(procRtlInitString.Addr(), 2, uintptr(unsafe.Pointer(destinationString)), uintptr(unsafe.Pointer(sourceString)), 0) + syscall.SyscallN(procRtlInitString.Addr(), uintptr(unsafe.Pointer(destinationString)), uintptr(unsafe.Pointer(sourceString))) return } func RtlInitUnicodeString(destinationString *NTUnicodeString, sourceString *uint16) { - syscall.Syscall(procRtlInitUnicodeString.Addr(), 2, uintptr(unsafe.Pointer(destinationString)), uintptr(unsafe.Pointer(sourceString)), 0) + syscall.SyscallN(procRtlInitUnicodeString.Addr(), uintptr(unsafe.Pointer(destinationString)), uintptr(unsafe.Pointer(sourceString))) return } func rtlNtStatusToDosErrorNoTeb(ntstatus NTStatus) (ret syscall.Errno) { - r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(ntstatus), 0, 0) + r0, _, _ := syscall.SyscallN(procRtlNtStatusToDosErrorNoTeb.Addr(), uintptr(ntstatus)) ret = syscall.Errno(r0) return } func clsidFromString(lpsz *uint16, pclsid *GUID) (ret error) { - r0, _, _ := syscall.Syscall(procCLSIDFromString.Addr(), 2, uintptr(unsafe.Pointer(lpsz)), uintptr(unsafe.Pointer(pclsid)), 0) + r0, _, _ := syscall.SyscallN(procCLSIDFromString.Addr(), uintptr(unsafe.Pointer(lpsz)), uintptr(unsafe.Pointer(pclsid))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -3761,7 +3780,7 @@ func clsidFromString(lpsz *uint16, pclsid *GUID) (ret error) { } func coCreateGuid(pguid *GUID) (ret error) { - r0, _, _ := syscall.Syscall(procCoCreateGuid.Addr(), 1, uintptr(unsafe.Pointer(pguid)), 0, 0) + r0, _, _ := syscall.SyscallN(procCoCreateGuid.Addr(), uintptr(unsafe.Pointer(pguid))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -3769,7 +3788,7 @@ func coCreateGuid(pguid *GUID) (ret error) { } func CoGetObject(name *uint16, bindOpts *BIND_OPTS3, guid *GUID, functionTable **uintptr) (ret error) { - r0, _, _ := syscall.Syscall6(procCoGetObject.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(bindOpts)), uintptr(unsafe.Pointer(guid)), uintptr(unsafe.Pointer(functionTable)), 0, 0) + r0, _, _ := syscall.SyscallN(procCoGetObject.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(bindOpts)), uintptr(unsafe.Pointer(guid)), uintptr(unsafe.Pointer(functionTable))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -3777,7 +3796,7 @@ func CoGetObject(name *uint16, bindOpts *BIND_OPTS3, guid *GUID, functionTable * } func CoInitializeEx(reserved uintptr, coInit uint32) (ret error) { - r0, _, _ := syscall.Syscall(procCoInitializeEx.Addr(), 2, uintptr(reserved), uintptr(coInit), 0) + r0, _, _ := syscall.SyscallN(procCoInitializeEx.Addr(), uintptr(reserved), uintptr(coInit)) if r0 != 0 { ret = syscall.Errno(r0) } @@ -3785,23 +3804,23 @@ func CoInitializeEx(reserved uintptr, coInit uint32) (ret error) { } func CoTaskMemFree(address unsafe.Pointer) { - syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(address), 0, 0) + syscall.SyscallN(procCoTaskMemFree.Addr(), uintptr(address)) return } func CoUninitialize() { - syscall.Syscall(procCoUninitialize.Addr(), 0, 0, 0, 0) + syscall.SyscallN(procCoUninitialize.Addr()) return } func stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) { - r0, _, _ := syscall.Syscall(procStringFromGUID2.Addr(), 3, uintptr(unsafe.Pointer(rguid)), uintptr(unsafe.Pointer(lpsz)), uintptr(cchMax)) + r0, _, _ := syscall.SyscallN(procStringFromGUID2.Addr(), uintptr(unsafe.Pointer(rguid)), uintptr(unsafe.Pointer(lpsz)), uintptr(cchMax)) chars = int32(r0) return } func EnumProcessModules(process Handle, module *Handle, cb uint32, cbNeeded *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procEnumProcessModules.Addr(), 4, uintptr(process), uintptr(unsafe.Pointer(module)), uintptr(cb), uintptr(unsafe.Pointer(cbNeeded)), 0, 0) + r1, _, e1 := syscall.SyscallN(procEnumProcessModules.Addr(), uintptr(process), uintptr(unsafe.Pointer(module)), uintptr(cb), uintptr(unsafe.Pointer(cbNeeded))) if r1 == 0 { err = errnoErr(e1) } @@ -3809,7 +3828,7 @@ func EnumProcessModules(process Handle, module *Handle, cb uint32, cbNeeded *uin } func EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *uint32, filterFlag uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procEnumProcessModulesEx.Addr(), 5, uintptr(process), uintptr(unsafe.Pointer(module)), uintptr(cb), uintptr(unsafe.Pointer(cbNeeded)), uintptr(filterFlag), 0) + r1, _, e1 := syscall.SyscallN(procEnumProcessModulesEx.Addr(), uintptr(process), uintptr(unsafe.Pointer(module)), uintptr(cb), uintptr(unsafe.Pointer(cbNeeded)), uintptr(filterFlag)) if r1 == 0 { err = errnoErr(e1) } @@ -3817,7 +3836,7 @@ func EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *u } func enumProcesses(processIds *uint32, nSize uint32, bytesReturned *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procEnumProcesses.Addr(), 3, uintptr(unsafe.Pointer(processIds)), uintptr(nSize), uintptr(unsafe.Pointer(bytesReturned))) + r1, _, e1 := syscall.SyscallN(procEnumProcesses.Addr(), uintptr(unsafe.Pointer(processIds)), uintptr(nSize), uintptr(unsafe.Pointer(bytesReturned))) if r1 == 0 { err = errnoErr(e1) } @@ -3825,7 +3844,7 @@ func enumProcesses(processIds *uint32, nSize uint32, bytesReturned *uint32) (err } func GetModuleBaseName(process Handle, module Handle, baseName *uint16, size uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetModuleBaseNameW.Addr(), 4, uintptr(process), uintptr(module), uintptr(unsafe.Pointer(baseName)), uintptr(size), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetModuleBaseNameW.Addr(), uintptr(process), uintptr(module), uintptr(unsafe.Pointer(baseName)), uintptr(size)) if r1 == 0 { err = errnoErr(e1) } @@ -3833,7 +3852,7 @@ func GetModuleBaseName(process Handle, module Handle, baseName *uint16, size uin } func GetModuleFileNameEx(process Handle, module Handle, filename *uint16, size uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetModuleFileNameExW.Addr(), 4, uintptr(process), uintptr(module), uintptr(unsafe.Pointer(filename)), uintptr(size), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetModuleFileNameExW.Addr(), uintptr(process), uintptr(module), uintptr(unsafe.Pointer(filename)), uintptr(size)) if r1 == 0 { err = errnoErr(e1) } @@ -3841,7 +3860,7 @@ func GetModuleFileNameEx(process Handle, module Handle, filename *uint16, size u } func GetModuleInformation(process Handle, module Handle, modinfo *ModuleInfo, cb uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetModuleInformation.Addr(), 4, uintptr(process), uintptr(module), uintptr(unsafe.Pointer(modinfo)), uintptr(cb), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetModuleInformation.Addr(), uintptr(process), uintptr(module), uintptr(unsafe.Pointer(modinfo)), uintptr(cb)) if r1 == 0 { err = errnoErr(e1) } @@ -3849,7 +3868,7 @@ func GetModuleInformation(process Handle, module Handle, modinfo *ModuleInfo, cb } func QueryWorkingSetEx(process Handle, pv uintptr, cb uint32) (err error) { - r1, _, e1 := syscall.Syscall(procQueryWorkingSetEx.Addr(), 3, uintptr(process), uintptr(pv), uintptr(cb)) + r1, _, e1 := syscall.SyscallN(procQueryWorkingSetEx.Addr(), uintptr(process), uintptr(pv), uintptr(cb)) if r1 == 0 { err = errnoErr(e1) } @@ -3861,7 +3880,7 @@ func SubscribeServiceChangeNotifications(service Handle, eventType uint32, callb if ret != nil { return } - r0, _, _ := syscall.Syscall6(procSubscribeServiceChangeNotifications.Addr(), 5, uintptr(service), uintptr(eventType), uintptr(callback), uintptr(callbackCtx), uintptr(unsafe.Pointer(subscription)), 0) + r0, _, _ := syscall.SyscallN(procSubscribeServiceChangeNotifications.Addr(), uintptr(service), uintptr(eventType), uintptr(callback), uintptr(callbackCtx), uintptr(unsafe.Pointer(subscription))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -3873,12 +3892,12 @@ func UnsubscribeServiceChangeNotifications(subscription uintptr) (err error) { if err != nil { return } - syscall.Syscall(procUnsubscribeServiceChangeNotifications.Addr(), 1, uintptr(subscription), 0, 0) + syscall.SyscallN(procUnsubscribeServiceChangeNotifications.Addr(), uintptr(subscription)) return } func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize))) + r1, _, e1 := syscall.SyscallN(procGetUserNameExW.Addr(), uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize))) if r1&0xff == 0 { err = errnoErr(e1) } @@ -3886,7 +3905,7 @@ func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err er } func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0) + r1, _, e1 := syscall.SyscallN(procTranslateNameW.Addr(), uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize))) if r1&0xff == 0 { err = errnoErr(e1) } @@ -3894,7 +3913,7 @@ func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint } func SetupDiBuildDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiBuildDriverInfoList.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType)) + r1, _, e1 := syscall.SyscallN(procSetupDiBuildDriverInfoList.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType)) if r1 == 0 { err = errnoErr(e1) } @@ -3902,7 +3921,7 @@ func SetupDiBuildDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoDa } func SetupDiCallClassInstaller(installFunction DI_FUNCTION, deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiCallClassInstaller.Addr(), 3, uintptr(installFunction), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData))) + r1, _, e1 := syscall.SyscallN(procSetupDiCallClassInstaller.Addr(), uintptr(installFunction), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData))) if r1 == 0 { err = errnoErr(e1) } @@ -3910,7 +3929,7 @@ func SetupDiCallClassInstaller(installFunction DI_FUNCTION, deviceInfoSet DevInf } func SetupDiCancelDriverInfoSearch(deviceInfoSet DevInfo) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiCancelDriverInfoSearch.Addr(), 1, uintptr(deviceInfoSet), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetupDiCancelDriverInfoSearch.Addr(), uintptr(deviceInfoSet)) if r1 == 0 { err = errnoErr(e1) } @@ -3918,7 +3937,7 @@ func SetupDiCancelDriverInfoSearch(deviceInfoSet DevInfo) (err error) { } func setupDiClassGuidsFromNameEx(className *uint16, classGuidList *GUID, classGuidListSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiClassGuidsFromNameExW.Addr(), 6, uintptr(unsafe.Pointer(className)), uintptr(unsafe.Pointer(classGuidList)), uintptr(classGuidListSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(unsafe.Pointer(machineName)), uintptr(reserved)) + r1, _, e1 := syscall.SyscallN(procSetupDiClassGuidsFromNameExW.Addr(), uintptr(unsafe.Pointer(className)), uintptr(unsafe.Pointer(classGuidList)), uintptr(classGuidListSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(unsafe.Pointer(machineName)), uintptr(reserved)) if r1 == 0 { err = errnoErr(e1) } @@ -3926,7 +3945,7 @@ func setupDiClassGuidsFromNameEx(className *uint16, classGuidList *GUID, classGu } func setupDiClassNameFromGuidEx(classGUID *GUID, className *uint16, classNameSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiClassNameFromGuidExW.Addr(), 6, uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(className)), uintptr(classNameSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(unsafe.Pointer(machineName)), uintptr(reserved)) + r1, _, e1 := syscall.SyscallN(procSetupDiClassNameFromGuidExW.Addr(), uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(className)), uintptr(classNameSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(unsafe.Pointer(machineName)), uintptr(reserved)) if r1 == 0 { err = errnoErr(e1) } @@ -3934,7 +3953,7 @@ func setupDiClassNameFromGuidEx(classGUID *GUID, className *uint16, classNameSiz } func setupDiCreateDeviceInfoListEx(classGUID *GUID, hwndParent uintptr, machineName *uint16, reserved uintptr) (handle DevInfo, err error) { - r0, _, e1 := syscall.Syscall6(procSetupDiCreateDeviceInfoListExW.Addr(), 4, uintptr(unsafe.Pointer(classGUID)), uintptr(hwndParent), uintptr(unsafe.Pointer(machineName)), uintptr(reserved), 0, 0) + r0, _, e1 := syscall.SyscallN(procSetupDiCreateDeviceInfoListExW.Addr(), uintptr(unsafe.Pointer(classGUID)), uintptr(hwndParent), uintptr(unsafe.Pointer(machineName)), uintptr(reserved)) handle = DevInfo(r0) if handle == DevInfo(InvalidHandle) { err = errnoErr(e1) @@ -3943,7 +3962,7 @@ func setupDiCreateDeviceInfoListEx(classGUID *GUID, hwndParent uintptr, machineN } func setupDiCreateDeviceInfo(deviceInfoSet DevInfo, DeviceName *uint16, classGUID *GUID, DeviceDescription *uint16, hwndParent uintptr, CreationFlags DICD, deviceInfoData *DevInfoData) (err error) { - r1, _, e1 := syscall.Syscall9(procSetupDiCreateDeviceInfoW.Addr(), 7, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(DeviceName)), uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(DeviceDescription)), uintptr(hwndParent), uintptr(CreationFlags), uintptr(unsafe.Pointer(deviceInfoData)), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetupDiCreateDeviceInfoW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(DeviceName)), uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(DeviceDescription)), uintptr(hwndParent), uintptr(CreationFlags), uintptr(unsafe.Pointer(deviceInfoData))) if r1 == 0 { err = errnoErr(e1) } @@ -3951,7 +3970,7 @@ func setupDiCreateDeviceInfo(deviceInfoSet DevInfo, DeviceName *uint16, classGUI } func SetupDiDestroyDeviceInfoList(deviceInfoSet DevInfo) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiDestroyDeviceInfoList.Addr(), 1, uintptr(deviceInfoSet), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetupDiDestroyDeviceInfoList.Addr(), uintptr(deviceInfoSet)) if r1 == 0 { err = errnoErr(e1) } @@ -3959,7 +3978,7 @@ func SetupDiDestroyDeviceInfoList(deviceInfoSet DevInfo) (err error) { } func SetupDiDestroyDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiDestroyDriverInfoList.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType)) + r1, _, e1 := syscall.SyscallN(procSetupDiDestroyDriverInfoList.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType)) if r1 == 0 { err = errnoErr(e1) } @@ -3967,7 +3986,7 @@ func SetupDiDestroyDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfo } func setupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex uint32, deviceInfoData *DevInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiEnumDeviceInfo.Addr(), 3, uintptr(deviceInfoSet), uintptr(memberIndex), uintptr(unsafe.Pointer(deviceInfoData))) + r1, _, e1 := syscall.SyscallN(procSetupDiEnumDeviceInfo.Addr(), uintptr(deviceInfoSet), uintptr(memberIndex), uintptr(unsafe.Pointer(deviceInfoData))) if r1 == 0 { err = errnoErr(e1) } @@ -3975,7 +3994,7 @@ func setupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex uint32, deviceInfo } func setupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex uint32, driverInfoData *DrvInfoData) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiEnumDriverInfoW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType), uintptr(memberIndex), uintptr(unsafe.Pointer(driverInfoData)), 0) + r1, _, e1 := syscall.SyscallN(procSetupDiEnumDriverInfoW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType), uintptr(memberIndex), uintptr(unsafe.Pointer(driverInfoData))) if r1 == 0 { err = errnoErr(e1) } @@ -3983,7 +4002,7 @@ func setupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, d } func setupDiGetClassDevsEx(classGUID *GUID, Enumerator *uint16, hwndParent uintptr, Flags DIGCF, deviceInfoSet DevInfo, machineName *uint16, reserved uintptr) (handle DevInfo, err error) { - r0, _, e1 := syscall.Syscall9(procSetupDiGetClassDevsExW.Addr(), 7, uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(Enumerator)), uintptr(hwndParent), uintptr(Flags), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(machineName)), uintptr(reserved), 0, 0) + r0, _, e1 := syscall.SyscallN(procSetupDiGetClassDevsExW.Addr(), uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(Enumerator)), uintptr(hwndParent), uintptr(Flags), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(machineName)), uintptr(reserved)) handle = DevInfo(r0) if handle == DevInfo(InvalidHandle) { err = errnoErr(e1) @@ -3992,7 +4011,7 @@ func setupDiGetClassDevsEx(classGUID *GUID, Enumerator *uint16, hwndParent uintp } func SetupDiGetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiGetClassInstallParamsW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(classInstallParams)), uintptr(classInstallParamsSize), uintptr(unsafe.Pointer(requiredSize)), 0) + r1, _, e1 := syscall.SyscallN(procSetupDiGetClassInstallParamsW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(classInstallParams)), uintptr(classInstallParamsSize), uintptr(unsafe.Pointer(requiredSize))) if r1 == 0 { err = errnoErr(e1) } @@ -4000,7 +4019,7 @@ func SetupDiGetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfo } func setupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo, deviceInfoSetDetailData *DevInfoListDetailData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiGetDeviceInfoListDetailW.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoSetDetailData)), 0) + r1, _, e1 := syscall.SyscallN(procSetupDiGetDeviceInfoListDetailW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoSetDetailData))) if r1 == 0 { err = errnoErr(e1) } @@ -4008,7 +4027,7 @@ func setupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo, deviceInfoSetDetailDa } func setupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiGetDeviceInstallParamsW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(deviceInstallParams))) + r1, _, e1 := syscall.SyscallN(procSetupDiGetDeviceInstallParamsW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(deviceInstallParams))) if r1 == 0 { err = errnoErr(e1) } @@ -4016,7 +4035,7 @@ func setupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInf } func setupDiGetDeviceInstanceId(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, instanceId *uint16, instanceIdSize uint32, instanceIdRequiredSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiGetDeviceInstanceIdW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(instanceId)), uintptr(instanceIdSize), uintptr(unsafe.Pointer(instanceIdRequiredSize)), 0) + r1, _, e1 := syscall.SyscallN(procSetupDiGetDeviceInstanceIdW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(instanceId)), uintptr(instanceIdSize), uintptr(unsafe.Pointer(instanceIdRequiredSize))) if r1 == 0 { err = errnoErr(e1) } @@ -4024,7 +4043,7 @@ func setupDiGetDeviceInstanceId(deviceInfoSet DevInfo, deviceInfoData *DevInfoDa } func setupDiGetDeviceProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, propertyKey *DEVPROPKEY, propertyType *DEVPROPTYPE, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procSetupDiGetDevicePropertyW.Addr(), 8, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(propertyKey)), uintptr(unsafe.Pointer(propertyType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(flags), 0) + r1, _, e1 := syscall.SyscallN(procSetupDiGetDevicePropertyW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(propertyKey)), uintptr(unsafe.Pointer(propertyType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(flags)) if r1 == 0 { err = errnoErr(e1) } @@ -4032,7 +4051,7 @@ func setupDiGetDeviceProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData } func setupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyRegDataType *uint32, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procSetupDiGetDeviceRegistryPropertyW.Addr(), 7, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(property), uintptr(unsafe.Pointer(propertyRegDataType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), uintptr(unsafe.Pointer(requiredSize)), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetupDiGetDeviceRegistryPropertyW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(property), uintptr(unsafe.Pointer(propertyRegDataType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), uintptr(unsafe.Pointer(requiredSize))) if r1 == 0 { err = errnoErr(e1) } @@ -4040,7 +4059,7 @@ func setupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *Dev } func setupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData, driverInfoDetailData *DrvInfoDetailData, driverInfoDetailDataSize uint32, requiredSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiGetDriverInfoDetailW.Addr(), 6, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData)), uintptr(unsafe.Pointer(driverInfoDetailData)), uintptr(driverInfoDetailDataSize), uintptr(unsafe.Pointer(requiredSize))) + r1, _, e1 := syscall.SyscallN(procSetupDiGetDriverInfoDetailW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData)), uintptr(unsafe.Pointer(driverInfoDetailData)), uintptr(driverInfoDetailDataSize), uintptr(unsafe.Pointer(requiredSize))) if r1 == 0 { err = errnoErr(e1) } @@ -4048,7 +4067,7 @@ func setupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoDa } func setupDiGetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiGetSelectedDevice.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), 0) + r1, _, e1 := syscall.SyscallN(procSetupDiGetSelectedDevice.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData))) if r1 == 0 { err = errnoErr(e1) } @@ -4056,7 +4075,7 @@ func setupDiGetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData } func setupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiGetSelectedDriverW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData))) + r1, _, e1 := syscall.SyscallN(procSetupDiGetSelectedDriverW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData))) if r1 == 0 { err = errnoErr(e1) } @@ -4064,7 +4083,7 @@ func setupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData } func SetupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (key Handle, err error) { - r0, _, e1 := syscall.Syscall6(procSetupDiOpenDevRegKey.Addr(), 6, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(Scope), uintptr(HwProfile), uintptr(KeyType), uintptr(samDesired)) + r0, _, e1 := syscall.SyscallN(procSetupDiOpenDevRegKey.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(Scope), uintptr(HwProfile), uintptr(KeyType), uintptr(samDesired)) key = Handle(r0) if key == InvalidHandle { err = errnoErr(e1) @@ -4073,7 +4092,7 @@ func SetupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, Sc } func SetupDiSetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiSetClassInstallParamsW.Addr(), 4, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(classInstallParams)), uintptr(classInstallParamsSize), 0, 0) + r1, _, e1 := syscall.SyscallN(procSetupDiSetClassInstallParamsW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(classInstallParams)), uintptr(classInstallParamsSize)) if r1 == 0 { err = errnoErr(e1) } @@ -4081,7 +4100,7 @@ func SetupDiSetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfo } func SetupDiSetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiSetDeviceInstallParamsW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(deviceInstallParams))) + r1, _, e1 := syscall.SyscallN(procSetupDiSetDeviceInstallParamsW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(deviceInstallParams))) if r1 == 0 { err = errnoErr(e1) } @@ -4089,7 +4108,7 @@ func SetupDiSetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInf } func setupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffer *byte, propertyBufferSize uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiSetDeviceRegistryPropertyW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(property), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), 0) + r1, _, e1 := syscall.SyscallN(procSetupDiSetDeviceRegistryPropertyW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(property), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize)) if r1 == 0 { err = errnoErr(e1) } @@ -4097,7 +4116,7 @@ func setupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *Dev } func SetupDiSetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiSetSelectedDevice.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), 0) + r1, _, e1 := syscall.SyscallN(procSetupDiSetSelectedDevice.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData))) if r1 == 0 { err = errnoErr(e1) } @@ -4105,7 +4124,7 @@ func SetupDiSetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData } func SetupDiSetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiSetSelectedDriverW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData))) + r1, _, e1 := syscall.SyscallN(procSetupDiSetSelectedDriverW.Addr(), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData))) if r1 == 0 { err = errnoErr(e1) } @@ -4113,7 +4132,7 @@ func SetupDiSetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData } func setupUninstallOEMInf(infFileName *uint16, flags SUOI, reserved uintptr) (err error) { - r1, _, e1 := syscall.Syscall(procSetupUninstallOEMInfW.Addr(), 3, uintptr(unsafe.Pointer(infFileName)), uintptr(flags), uintptr(reserved)) + r1, _, e1 := syscall.SyscallN(procSetupUninstallOEMInfW.Addr(), uintptr(unsafe.Pointer(infFileName)), uintptr(flags), uintptr(reserved)) if r1 == 0 { err = errnoErr(e1) } @@ -4121,7 +4140,7 @@ func setupUninstallOEMInf(infFileName *uint16, flags SUOI, reserved uintptr) (er } func commandLineToArgv(cmd *uint16, argc *int32) (argv **uint16, err error) { - r0, _, e1 := syscall.Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0) + r0, _, e1 := syscall.SyscallN(procCommandLineToArgvW.Addr(), uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc))) argv = (**uint16)(unsafe.Pointer(r0)) if argv == nil { err = errnoErr(e1) @@ -4130,7 +4149,7 @@ func commandLineToArgv(cmd *uint16, argc *int32) (argv **uint16, err error) { } func shGetKnownFolderPath(id *KNOWNFOLDERID, flags uint32, token Token, path **uint16) (ret error) { - r0, _, _ := syscall.Syscall6(procSHGetKnownFolderPath.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(flags), uintptr(token), uintptr(unsafe.Pointer(path)), 0, 0) + r0, _, _ := syscall.SyscallN(procSHGetKnownFolderPath.Addr(), uintptr(unsafe.Pointer(id)), uintptr(flags), uintptr(token), uintptr(unsafe.Pointer(path))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -4138,7 +4157,7 @@ func shGetKnownFolderPath(id *KNOWNFOLDERID, flags uint32, token Token, path **u } func ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *uint16, showCmd int32) (err error) { - r1, _, e1 := syscall.Syscall6(procShellExecuteW.Addr(), 6, uintptr(hwnd), uintptr(unsafe.Pointer(verb)), uintptr(unsafe.Pointer(file)), uintptr(unsafe.Pointer(args)), uintptr(unsafe.Pointer(cwd)), uintptr(showCmd)) + r1, _, e1 := syscall.SyscallN(procShellExecuteW.Addr(), uintptr(hwnd), uintptr(unsafe.Pointer(verb)), uintptr(unsafe.Pointer(file)), uintptr(unsafe.Pointer(args)), uintptr(unsafe.Pointer(cwd)), uintptr(showCmd)) if r1 <= 32 { err = errnoErr(e1) } @@ -4146,12 +4165,12 @@ func ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *ui } func EnumChildWindows(hwnd HWND, enumFunc uintptr, param unsafe.Pointer) { - syscall.Syscall(procEnumChildWindows.Addr(), 3, uintptr(hwnd), uintptr(enumFunc), uintptr(param)) + syscall.SyscallN(procEnumChildWindows.Addr(), uintptr(hwnd), uintptr(enumFunc), uintptr(param)) return } func EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) { - r1, _, e1 := syscall.Syscall(procEnumWindows.Addr(), 2, uintptr(enumFunc), uintptr(param), 0) + r1, _, e1 := syscall.SyscallN(procEnumWindows.Addr(), uintptr(enumFunc), uintptr(param)) if r1 == 0 { err = errnoErr(e1) } @@ -4159,7 +4178,7 @@ func EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) { } func ExitWindowsEx(flags uint32, reason uint32) (err error) { - r1, _, e1 := syscall.Syscall(procExitWindowsEx.Addr(), 2, uintptr(flags), uintptr(reason), 0) + r1, _, e1 := syscall.SyscallN(procExitWindowsEx.Addr(), uintptr(flags), uintptr(reason)) if r1 == 0 { err = errnoErr(e1) } @@ -4167,7 +4186,7 @@ func ExitWindowsEx(flags uint32, reason uint32) (err error) { } func GetClassName(hwnd HWND, className *uint16, maxCount int32) (copied int32, err error) { - r0, _, e1 := syscall.Syscall(procGetClassNameW.Addr(), 3, uintptr(hwnd), uintptr(unsafe.Pointer(className)), uintptr(maxCount)) + r0, _, e1 := syscall.SyscallN(procGetClassNameW.Addr(), uintptr(hwnd), uintptr(unsafe.Pointer(className)), uintptr(maxCount)) copied = int32(r0) if copied == 0 { err = errnoErr(e1) @@ -4176,19 +4195,19 @@ func GetClassName(hwnd HWND, className *uint16, maxCount int32) (copied int32, e } func GetDesktopWindow() (hwnd HWND) { - r0, _, _ := syscall.Syscall(procGetDesktopWindow.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procGetDesktopWindow.Addr()) hwnd = HWND(r0) return } func GetForegroundWindow() (hwnd HWND) { - r0, _, _ := syscall.Syscall(procGetForegroundWindow.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procGetForegroundWindow.Addr()) hwnd = HWND(r0) return } func GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) { - r1, _, e1 := syscall.Syscall(procGetGUIThreadInfo.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(info)), 0) + r1, _, e1 := syscall.SyscallN(procGetGUIThreadInfo.Addr(), uintptr(thread), uintptr(unsafe.Pointer(info))) if r1 == 0 { err = errnoErr(e1) } @@ -4196,19 +4215,19 @@ func GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) { } func GetKeyboardLayout(tid uint32) (hkl Handle) { - r0, _, _ := syscall.Syscall(procGetKeyboardLayout.Addr(), 1, uintptr(tid), 0, 0) + r0, _, _ := syscall.SyscallN(procGetKeyboardLayout.Addr(), uintptr(tid)) hkl = Handle(r0) return } func GetShellWindow() (shellWindow HWND) { - r0, _, _ := syscall.Syscall(procGetShellWindow.Addr(), 0, 0, 0, 0) + r0, _, _ := syscall.SyscallN(procGetShellWindow.Addr()) shellWindow = HWND(r0) return } func GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetWindowThreadProcessId.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(pid)), 0) + r0, _, e1 := syscall.SyscallN(procGetWindowThreadProcessId.Addr(), uintptr(hwnd), uintptr(unsafe.Pointer(pid))) tid = uint32(r0) if tid == 0 { err = errnoErr(e1) @@ -4217,25 +4236,25 @@ func GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) { } func IsWindow(hwnd HWND) (isWindow bool) { - r0, _, _ := syscall.Syscall(procIsWindow.Addr(), 1, uintptr(hwnd), 0, 0) + r0, _, _ := syscall.SyscallN(procIsWindow.Addr(), uintptr(hwnd)) isWindow = r0 != 0 return } func IsWindowUnicode(hwnd HWND) (isUnicode bool) { - r0, _, _ := syscall.Syscall(procIsWindowUnicode.Addr(), 1, uintptr(hwnd), 0, 0) + r0, _, _ := syscall.SyscallN(procIsWindowUnicode.Addr(), uintptr(hwnd)) isUnicode = r0 != 0 return } func IsWindowVisible(hwnd HWND) (isVisible bool) { - r0, _, _ := syscall.Syscall(procIsWindowVisible.Addr(), 1, uintptr(hwnd), 0, 0) + r0, _, _ := syscall.SyscallN(procIsWindowVisible.Addr(), uintptr(hwnd)) isVisible = r0 != 0 return } func LoadKeyboardLayout(name *uint16, flags uint32) (hkl Handle, err error) { - r0, _, e1 := syscall.Syscall(procLoadKeyboardLayoutW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(flags), 0) + r0, _, e1 := syscall.SyscallN(procLoadKeyboardLayoutW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(flags)) hkl = Handle(r0) if hkl == 0 { err = errnoErr(e1) @@ -4244,7 +4263,7 @@ func LoadKeyboardLayout(name *uint16, flags uint32) (hkl Handle, err error) { } func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) { - r0, _, e1 := syscall.Syscall6(procMessageBoxW.Addr(), 4, uintptr(hwnd), uintptr(unsafe.Pointer(text)), uintptr(unsafe.Pointer(caption)), uintptr(boxtype), 0, 0) + r0, _, e1 := syscall.SyscallN(procMessageBoxW.Addr(), uintptr(hwnd), uintptr(unsafe.Pointer(text)), uintptr(unsafe.Pointer(caption)), uintptr(boxtype)) ret = int32(r0) if ret == 0 { err = errnoErr(e1) @@ -4253,13 +4272,13 @@ func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret i } func ToUnicodeEx(vkey uint32, scancode uint32, keystate *byte, pwszBuff *uint16, cchBuff int32, flags uint32, hkl Handle) (ret int32) { - r0, _, _ := syscall.Syscall9(procToUnicodeEx.Addr(), 7, uintptr(vkey), uintptr(scancode), uintptr(unsafe.Pointer(keystate)), uintptr(unsafe.Pointer(pwszBuff)), uintptr(cchBuff), uintptr(flags), uintptr(hkl), 0, 0) + r0, _, _ := syscall.SyscallN(procToUnicodeEx.Addr(), uintptr(vkey), uintptr(scancode), uintptr(unsafe.Pointer(keystate)), uintptr(unsafe.Pointer(pwszBuff)), uintptr(cchBuff), uintptr(flags), uintptr(hkl)) ret = int32(r0) return } func UnloadKeyboardLayout(hkl Handle) (err error) { - r1, _, e1 := syscall.Syscall(procUnloadKeyboardLayout.Addr(), 1, uintptr(hkl), 0, 0) + r1, _, e1 := syscall.SyscallN(procUnloadKeyboardLayout.Addr(), uintptr(hkl)) if r1 == 0 { err = errnoErr(e1) } @@ -4271,7 +4290,7 @@ func CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) ( if inheritExisting { _p0 = 1 } - r1, _, e1 := syscall.Syscall(procCreateEnvironmentBlock.Addr(), 3, uintptr(unsafe.Pointer(block)), uintptr(token), uintptr(_p0)) + r1, _, e1 := syscall.SyscallN(procCreateEnvironmentBlock.Addr(), uintptr(unsafe.Pointer(block)), uintptr(token), uintptr(_p0)) if r1 == 0 { err = errnoErr(e1) } @@ -4279,7 +4298,7 @@ func CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) ( } func DestroyEnvironmentBlock(block *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procDestroyEnvironmentBlock.Addr(), 1, uintptr(unsafe.Pointer(block)), 0, 0) + r1, _, e1 := syscall.SyscallN(procDestroyEnvironmentBlock.Addr(), uintptr(unsafe.Pointer(block))) if r1 == 0 { err = errnoErr(e1) } @@ -4287,7 +4306,7 @@ func DestroyEnvironmentBlock(block *uint16) (err error) { } func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetUserProfileDirectoryW.Addr(), 3, uintptr(t), uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen))) + r1, _, e1 := syscall.SyscallN(procGetUserProfileDirectoryW.Addr(), uintptr(t), uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen))) if r1 == 0 { err = errnoErr(e1) } @@ -4304,7 +4323,7 @@ func GetFileVersionInfoSize(filename string, zeroHandle *Handle) (bufSize uint32 } func _GetFileVersionInfoSize(filename *uint16, zeroHandle *Handle) (bufSize uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetFileVersionInfoSizeW.Addr(), 2, uintptr(unsafe.Pointer(filename)), uintptr(unsafe.Pointer(zeroHandle)), 0) + r0, _, e1 := syscall.SyscallN(procGetFileVersionInfoSizeW.Addr(), uintptr(unsafe.Pointer(filename)), uintptr(unsafe.Pointer(zeroHandle))) bufSize = uint32(r0) if bufSize == 0 { err = errnoErr(e1) @@ -4322,7 +4341,7 @@ func GetFileVersionInfo(filename string, handle uint32, bufSize uint32, buffer u } func _GetFileVersionInfo(filename *uint16, handle uint32, bufSize uint32, buffer unsafe.Pointer) (err error) { - r1, _, e1 := syscall.Syscall6(procGetFileVersionInfoW.Addr(), 4, uintptr(unsafe.Pointer(filename)), uintptr(handle), uintptr(bufSize), uintptr(buffer), 0, 0) + r1, _, e1 := syscall.SyscallN(procGetFileVersionInfoW.Addr(), uintptr(unsafe.Pointer(filename)), uintptr(handle), uintptr(bufSize), uintptr(buffer)) if r1 == 0 { err = errnoErr(e1) } @@ -4339,7 +4358,7 @@ func VerQueryValue(block unsafe.Pointer, subBlock string, pointerToBufferPointer } func _VerQueryValue(block unsafe.Pointer, subBlock *uint16, pointerToBufferPointer unsafe.Pointer, bufSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procVerQueryValueW.Addr(), 4, uintptr(block), uintptr(unsafe.Pointer(subBlock)), uintptr(pointerToBufferPointer), uintptr(unsafe.Pointer(bufSize)), 0, 0) + r1, _, e1 := syscall.SyscallN(procVerQueryValueW.Addr(), uintptr(block), uintptr(unsafe.Pointer(subBlock)), uintptr(pointerToBufferPointer), uintptr(unsafe.Pointer(bufSize))) if r1 == 0 { err = errnoErr(e1) } @@ -4347,7 +4366,7 @@ func _VerQueryValue(block unsafe.Pointer, subBlock *uint16, pointerToBufferPoint } func TimeBeginPeriod(period uint32) (err error) { - r1, _, e1 := syscall.Syscall(proctimeBeginPeriod.Addr(), 1, uintptr(period), 0, 0) + r1, _, e1 := syscall.SyscallN(proctimeBeginPeriod.Addr(), uintptr(period)) if r1 != 0 { err = errnoErr(e1) } @@ -4355,7 +4374,7 @@ func TimeBeginPeriod(period uint32) (err error) { } func TimeEndPeriod(period uint32) (err error) { - r1, _, e1 := syscall.Syscall(proctimeEndPeriod.Addr(), 1, uintptr(period), 0, 0) + r1, _, e1 := syscall.SyscallN(proctimeEndPeriod.Addr(), uintptr(period)) if r1 != 0 { err = errnoErr(e1) } @@ -4363,7 +4382,7 @@ func TimeEndPeriod(period uint32) (err error) { } func WinVerifyTrustEx(hwnd HWND, actionId *GUID, data *WinTrustData) (ret error) { - r0, _, _ := syscall.Syscall(procWinVerifyTrustEx.Addr(), 3, uintptr(hwnd), uintptr(unsafe.Pointer(actionId)), uintptr(unsafe.Pointer(data))) + r0, _, _ := syscall.SyscallN(procWinVerifyTrustEx.Addr(), uintptr(hwnd), uintptr(unsafe.Pointer(actionId)), uintptr(unsafe.Pointer(data))) if r0 != 0 { ret = syscall.Errno(r0) } @@ -4371,12 +4390,12 @@ func WinVerifyTrustEx(hwnd HWND, actionId *GUID, data *WinTrustData) (ret error) } func FreeAddrInfoW(addrinfo *AddrinfoW) { - syscall.Syscall(procFreeAddrInfoW.Addr(), 1, uintptr(unsafe.Pointer(addrinfo)), 0, 0) + syscall.SyscallN(procFreeAddrInfoW.Addr(), uintptr(unsafe.Pointer(addrinfo))) return } func GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) { - r0, _, _ := syscall.Syscall6(procGetAddrInfoW.Addr(), 4, uintptr(unsafe.Pointer(nodename)), uintptr(unsafe.Pointer(servicename)), uintptr(unsafe.Pointer(hints)), uintptr(unsafe.Pointer(result)), 0, 0) + r0, _, _ := syscall.SyscallN(procGetAddrInfoW.Addr(), uintptr(unsafe.Pointer(nodename)), uintptr(unsafe.Pointer(servicename)), uintptr(unsafe.Pointer(hints)), uintptr(unsafe.Pointer(result))) if r0 != 0 { sockerr = syscall.Errno(r0) } @@ -4384,15 +4403,23 @@ func GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, resul } func WSACleanup() (err error) { - r1, _, e1 := syscall.Syscall(procWSACleanup.Addr(), 0, 0, 0, 0) + r1, _, e1 := syscall.SyscallN(procWSACleanup.Addr()) if r1 == socket_error { err = errnoErr(e1) } return } +func WSADuplicateSocket(s Handle, processID uint32, info *WSAProtocolInfo) (err error) { + r1, _, e1 := syscall.SyscallN(procWSADuplicateSocketW.Addr(), uintptr(s), uintptr(processID), uintptr(unsafe.Pointer(info))) + if r1 != 0 { + err = errnoErr(e1) + } + return +} + func WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) { - r0, _, e1 := syscall.Syscall(procWSAEnumProtocolsW.Addr(), 3, uintptr(unsafe.Pointer(protocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufferLength))) + r0, _, e1 := syscall.SyscallN(procWSAEnumProtocolsW.Addr(), uintptr(unsafe.Pointer(protocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufferLength))) n = int32(r0) if n == -1 { err = errnoErr(e1) @@ -4405,7 +4432,7 @@ func WSAGetOverlappedResult(h Handle, o *Overlapped, bytes *uint32, wait bool, f if wait { _p0 = 1 } - r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) + r1, _, e1 := syscall.SyscallN(procWSAGetOverlappedResult.Addr(), uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags))) if r1 == 0 { err = errnoErr(e1) } @@ -4413,7 +4440,7 @@ func WSAGetOverlappedResult(h Handle, o *Overlapped, bytes *uint32, wait bool, f } func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) { - r1, _, e1 := syscall.Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine)) + r1, _, e1 := syscall.SyscallN(procWSAIoctl.Addr(), uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine)) if r1 == socket_error { err = errnoErr(e1) } @@ -4421,7 +4448,7 @@ func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbo } func WSALookupServiceBegin(querySet *WSAQUERYSET, flags uint32, handle *Handle) (err error) { - r1, _, e1 := syscall.Syscall(procWSALookupServiceBeginW.Addr(), 3, uintptr(unsafe.Pointer(querySet)), uintptr(flags), uintptr(unsafe.Pointer(handle))) + r1, _, e1 := syscall.SyscallN(procWSALookupServiceBeginW.Addr(), uintptr(unsafe.Pointer(querySet)), uintptr(flags), uintptr(unsafe.Pointer(handle))) if r1 == socket_error { err = errnoErr(e1) } @@ -4429,7 +4456,7 @@ func WSALookupServiceBegin(querySet *WSAQUERYSET, flags uint32, handle *Handle) } func WSALookupServiceEnd(handle Handle) (err error) { - r1, _, e1 := syscall.Syscall(procWSALookupServiceEnd.Addr(), 1, uintptr(handle), 0, 0) + r1, _, e1 := syscall.SyscallN(procWSALookupServiceEnd.Addr(), uintptr(handle)) if r1 == socket_error { err = errnoErr(e1) } @@ -4437,7 +4464,7 @@ func WSALookupServiceEnd(handle Handle) (err error) { } func WSALookupServiceNext(handle Handle, flags uint32, size *int32, querySet *WSAQUERYSET) (err error) { - r1, _, e1 := syscall.Syscall6(procWSALookupServiceNextW.Addr(), 4, uintptr(handle), uintptr(flags), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(querySet)), 0, 0) + r1, _, e1 := syscall.SyscallN(procWSALookupServiceNextW.Addr(), uintptr(handle), uintptr(flags), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(querySet))) if r1 == socket_error { err = errnoErr(e1) } @@ -4445,7 +4472,7 @@ func WSALookupServiceNext(handle Handle, flags uint32, size *int32, querySet *WS } func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) { - r1, _, e1 := syscall.Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) + r1, _, e1 := syscall.SyscallN(procWSARecv.Addr(), uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) if r1 == socket_error { err = errnoErr(e1) } @@ -4453,7 +4480,7 @@ func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32 } func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) { - r1, _, e1 := syscall.Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + r1, _, e1 := syscall.SyscallN(procWSARecvFrom.Addr(), uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) if r1 == socket_error { err = errnoErr(e1) } @@ -4461,7 +4488,7 @@ func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *ui } func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) { - r1, _, e1 := syscall.Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) + r1, _, e1 := syscall.SyscallN(procWSASend.Addr(), uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) if r1 == socket_error { err = errnoErr(e1) } @@ -4469,7 +4496,7 @@ func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, } func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) { - r1, _, e1 := syscall.Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + r1, _, e1 := syscall.SyscallN(procWSASendTo.Addr(), uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) if r1 == socket_error { err = errnoErr(e1) } @@ -4477,7 +4504,7 @@ func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32 } func WSASocket(af int32, typ int32, protocol int32, protoInfo *WSAProtocolInfo, group uint32, flags uint32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protoInfo)), uintptr(group), uintptr(flags)) + r0, _, e1 := syscall.SyscallN(procWSASocketW.Addr(), uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protoInfo)), uintptr(group), uintptr(flags)) handle = Handle(r0) if handle == InvalidHandle { err = errnoErr(e1) @@ -4486,7 +4513,7 @@ func WSASocket(af int32, typ int32, protocol int32, protoInfo *WSAProtocolInfo, } func WSAStartup(verreq uint32, data *WSAData) (sockerr error) { - r0, _, _ := syscall.Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0) + r0, _, _ := syscall.SyscallN(procWSAStartup.Addr(), uintptr(verreq), uintptr(unsafe.Pointer(data))) if r0 != 0 { sockerr = syscall.Errno(r0) } @@ -4494,7 +4521,7 @@ func WSAStartup(verreq uint32, data *WSAData) (sockerr error) { } func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) { - r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + r1, _, e1 := syscall.SyscallN(procbind.Addr(), uintptr(s), uintptr(name), uintptr(namelen)) if r1 == socket_error { err = errnoErr(e1) } @@ -4502,7 +4529,7 @@ func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) { } func Closesocket(s Handle) (err error) { - r1, _, e1 := syscall.Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0) + r1, _, e1 := syscall.SyscallN(procclosesocket.Addr(), uintptr(s)) if r1 == socket_error { err = errnoErr(e1) } @@ -4510,7 +4537,7 @@ func Closesocket(s Handle) (err error) { } func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) { - r1, _, e1 := syscall.Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + r1, _, e1 := syscall.SyscallN(procconnect.Addr(), uintptr(s), uintptr(name), uintptr(namelen)) if r1 == socket_error { err = errnoErr(e1) } @@ -4527,7 +4554,7 @@ func GetHostByName(name string) (h *Hostent, err error) { } func _GetHostByName(name *byte) (h *Hostent, err error) { - r0, _, e1 := syscall.Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + r0, _, e1 := syscall.SyscallN(procgethostbyname.Addr(), uintptr(unsafe.Pointer(name))) h = (*Hostent)(unsafe.Pointer(r0)) if h == nil { err = errnoErr(e1) @@ -4536,7 +4563,7 @@ func _GetHostByName(name *byte) (h *Hostent, err error) { } func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { - r1, _, e1 := syscall.Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r1, _, e1 := syscall.SyscallN(procgetpeername.Addr(), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if r1 == socket_error { err = errnoErr(e1) } @@ -4553,7 +4580,7 @@ func GetProtoByName(name string) (p *Protoent, err error) { } func _GetProtoByName(name *byte) (p *Protoent, err error) { - r0, _, e1 := syscall.Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + r0, _, e1 := syscall.SyscallN(procgetprotobyname.Addr(), uintptr(unsafe.Pointer(name))) p = (*Protoent)(unsafe.Pointer(r0)) if p == nil { err = errnoErr(e1) @@ -4576,7 +4603,7 @@ func GetServByName(name string, proto string) (s *Servent, err error) { } func _GetServByName(name *byte, proto *byte) (s *Servent, err error) { - r0, _, e1 := syscall.Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(proto)), 0) + r0, _, e1 := syscall.SyscallN(procgetservbyname.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(proto))) s = (*Servent)(unsafe.Pointer(r0)) if s == nil { err = errnoErr(e1) @@ -4585,7 +4612,7 @@ func _GetServByName(name *byte, proto *byte) (s *Servent, err error) { } func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { - r1, _, e1 := syscall.Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r1, _, e1 := syscall.SyscallN(procgetsockname.Addr(), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if r1 == socket_error { err = errnoErr(e1) } @@ -4593,7 +4620,7 @@ func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { } func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) { - r1, _, e1 := syscall.Syscall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(unsafe.Pointer(optlen)), 0) + r1, _, e1 := syscall.SyscallN(procgetsockopt.Addr(), uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(unsafe.Pointer(optlen))) if r1 == socket_error { err = errnoErr(e1) } @@ -4601,7 +4628,7 @@ func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int3 } func listen(s Handle, backlog int32) (err error) { - r1, _, e1 := syscall.Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0) + r1, _, e1 := syscall.SyscallN(proclisten.Addr(), uintptr(s), uintptr(backlog)) if r1 == socket_error { err = errnoErr(e1) } @@ -4609,7 +4636,7 @@ func listen(s Handle, backlog int32) (err error) { } func Ntohs(netshort uint16) (u uint16) { - r0, _, _ := syscall.Syscall(procntohs.Addr(), 1, uintptr(netshort), 0, 0) + r0, _, _ := syscall.SyscallN(procntohs.Addr(), uintptr(netshort)) u = uint16(r0) return } @@ -4619,7 +4646,7 @@ func recvfrom(s Handle, buf []byte, flags int32, from *RawSockaddrAny, fromlen * if len(buf) > 0 { _p0 = &buf[0] } - r0, _, e1 := syscall.Syscall6(procrecvfrom.Addr(), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + r0, _, e1 := syscall.SyscallN(procrecvfrom.Addr(), uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) n = int32(r0) if n == -1 { err = errnoErr(e1) @@ -4632,7 +4659,7 @@ func sendto(s Handle, buf []byte, flags int32, to unsafe.Pointer, tolen int32) ( if len(buf) > 0 { _p0 = &buf[0] } - r1, _, e1 := syscall.Syscall6(procsendto.Addr(), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(tolen)) + r1, _, e1 := syscall.SyscallN(procsendto.Addr(), uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(tolen)) if r1 == socket_error { err = errnoErr(e1) } @@ -4640,7 +4667,7 @@ func sendto(s Handle, buf []byte, flags int32, to unsafe.Pointer, tolen int32) ( } func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) { - r1, _, e1 := syscall.Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0) + r1, _, e1 := syscall.SyscallN(procsetsockopt.Addr(), uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen)) if r1 == socket_error { err = errnoErr(e1) } @@ -4648,7 +4675,7 @@ func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32 } func shutdown(s Handle, how int32) (err error) { - r1, _, e1 := syscall.Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0) + r1, _, e1 := syscall.SyscallN(procshutdown.Addr(), uintptr(s), uintptr(how)) if r1 == socket_error { err = errnoErr(e1) } @@ -4656,7 +4683,7 @@ func shutdown(s Handle, how int32) (err error) { } func socket(af int32, typ int32, protocol int32) (handle Handle, err error) { - r0, _, e1 := syscall.Syscall(procsocket.Addr(), 3, uintptr(af), uintptr(typ), uintptr(protocol)) + r0, _, e1 := syscall.SyscallN(procsocket.Addr(), uintptr(af), uintptr(typ), uintptr(protocol)) handle = Handle(r0) if handle == InvalidHandle { err = errnoErr(e1) @@ -4665,7 +4692,7 @@ func socket(af int32, typ int32, protocol int32) (handle Handle, err error) { } func WTSEnumerateSessions(handle Handle, reserved uint32, version uint32, sessions **WTS_SESSION_INFO, count *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procWTSEnumerateSessionsW.Addr(), 5, uintptr(handle), uintptr(reserved), uintptr(version), uintptr(unsafe.Pointer(sessions)), uintptr(unsafe.Pointer(count)), 0) + r1, _, e1 := syscall.SyscallN(procWTSEnumerateSessionsW.Addr(), uintptr(handle), uintptr(reserved), uintptr(version), uintptr(unsafe.Pointer(sessions)), uintptr(unsafe.Pointer(count))) if r1 == 0 { err = errnoErr(e1) } @@ -4673,12 +4700,12 @@ func WTSEnumerateSessions(handle Handle, reserved uint32, version uint32, sessio } func WTSFreeMemory(ptr uintptr) { - syscall.Syscall(procWTSFreeMemory.Addr(), 1, uintptr(ptr), 0, 0) + syscall.SyscallN(procWTSFreeMemory.Addr(), uintptr(ptr)) return } func WTSQueryUserToken(session uint32, token *Token) (err error) { - r1, _, e1 := syscall.Syscall(procWTSQueryUserToken.Addr(), 2, uintptr(session), uintptr(unsafe.Pointer(token)), 0) + r1, _, e1 := syscall.SyscallN(procWTSQueryUserToken.Addr(), uintptr(session), uintptr(unsafe.Pointer(token))) if r1 == 0 { err = errnoErr(e1) } diff --git a/vendor/modules.txt b/vendor/modules.txt index cbc89a7b..4ee56b9d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,6 +1,7 @@ # github.com/NVIDIA/go-nvlib v0.8.1 ## explicit; go 1.20 github.com/NVIDIA/go-nvlib/pkg/nvlib/device +github.com/NVIDIA/go-nvlib/pkg/nvlib/info github.com/NVIDIA/go-nvlib/pkg/nvpci github.com/NVIDIA/go-nvlib/pkg/nvpci/bytes github.com/NVIDIA/go-nvlib/pkg/nvpci/mmio @@ -11,6 +12,32 @@ github.com/NVIDIA/go-nvml/pkg/dl github.com/NVIDIA/go-nvml/pkg/nvml github.com/NVIDIA/go-nvml/pkg/nvml/mock github.com/NVIDIA/go-nvml/pkg/nvml/mock/dgxa100 +# github.com/NVIDIA/nvidia-container-toolkit v1.18.0 => ../container-toolkit +## explicit; go 1.24.0 +github.com/NVIDIA/nvidia-container-toolkit/internal/config/image +github.com/NVIDIA/nvidia-container-toolkit/internal/discover +github.com/NVIDIA/nvidia-container-toolkit/internal/dxcore +github.com/NVIDIA/nvidia-container-toolkit/internal/edits +github.com/NVIDIA/nvidia-container-toolkit/internal/info/drm +github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc +github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices +github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache +github.com/NVIDIA/nvidia-container-toolkit/internal/logger +github.com/NVIDIA/nvidia-container-toolkit/internal/lookup +github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root +github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks +github.com/NVIDIA/nvidia-container-toolkit/internal/nvcaps +github.com/NVIDIA/nvidia-container-toolkit/internal/nvsandboxutils +github.com/NVIDIA/nvidia-container-toolkit/internal/oci +github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/dgpu +github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra +github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv +github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi +github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec +github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform +github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/noop +github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root +github.com/NVIDIA/nvidia-container-toolkit/pkg/system/nvdevices # github.com/coreos/go-systemd/v22 v22.6.0 ## explicit; go 1.23 github.com/coreos/go-systemd/v22/dbus @@ -24,6 +51,9 @@ github.com/davecgh/go-spew/spew ## explicit; go 1.13 github.com/emicklei/go-restful/v3 github.com/emicklei/go-restful/v3/log +# github.com/fsnotify/fsnotify v1.7.0 +## explicit; go 1.17 +github.com/fsnotify/fsnotify # github.com/fxamacker/cbor/v2 v2.7.0 ## explicit; go 1.17 github.com/fxamacker/cbor/v2 @@ -84,6 +114,14 @@ github.com/modern-go/reflect2 # github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 ## explicit github.com/munnerz/goautoneg +# github.com/opencontainers/runtime-spec v1.2.1 +## explicit +github.com/opencontainers/runtime-spec/specs-go +# github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 +## explicit; go 1.16 +github.com/opencontainers/runtime-tools/generate +github.com/opencontainers/runtime-tools/generate/seccomp +github.com/opencontainers/runtime-tools/validate/capabilities # github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors @@ -104,6 +142,9 @@ github.com/spf13/pflag github.com/stretchr/testify/assert github.com/stretchr/testify/assert/yaml github.com/stretchr/testify/require +# github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 +## explicit +github.com/syndtr/gocapability/capability # github.com/urfave/cli/v2 v2.27.7 ## explicit; go 1.18 github.com/urfave/cli/v2 @@ -116,6 +157,9 @@ github.com/xrash/smetrics # go.yaml.in/yaml/v2 v2.4.2 ## explicit; go 1.15 go.yaml.in/yaml/v2 +# golang.org/x/mod v0.29.0 +## explicit; go 1.24.0 +golang.org/x/mod/semver # golang.org/x/net v0.38.0 ## explicit; go 1.23.0 golang.org/x/net/http/httpguts @@ -127,8 +171,8 @@ golang.org/x/net/internal/httpcommon ## explicit; go 1.23.0 golang.org/x/oauth2 golang.org/x/oauth2/internal -# golang.org/x/sys v0.31.0 -## explicit; go 1.23.0 +# golang.org/x/sys v0.37.0 +## explicit; go 1.24.0 golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows @@ -493,3 +537,12 @@ sigs.k8s.io/structured-merge-diff/v4/value ## explicit; go 1.22 sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 +# tags.cncf.io/container-device-interface v1.0.1 +## explicit; go 1.20 +tags.cncf.io/container-device-interface/internal/validation +tags.cncf.io/container-device-interface/internal/validation/k8s +tags.cncf.io/container-device-interface/pkg/cdi +tags.cncf.io/container-device-interface/pkg/parser +# tags.cncf.io/container-device-interface/specs-go v1.0.0 +## explicit; go 1.19 +tags.cncf.io/container-device-interface/specs-go diff --git a/vendor/tags.cncf.io/container-device-interface/LICENSE b/vendor/tags.cncf.io/container-device-interface/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor 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, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/tags.cncf.io/container-device-interface/internal/validation/k8s/objectmeta.go b/vendor/tags.cncf.io/container-device-interface/internal/validation/k8s/objectmeta.go new file mode 100644 index 00000000..fb86c67a --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/internal/validation/k8s/objectmeta.go @@ -0,0 +1,56 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Adapted from k8s.io/apimachinery/pkg/api/validation: +// https://github.com/kubernetes/apimachinery/blob/7687996c715ee7d5c8cf1e3215e607eb065a4221/pkg/api/validation/objectmeta.go + +package k8s + +import ( + "errors" + "fmt" + "strings" +) + +// TotalAnnotationSizeLimitB defines the maximum size of all annotations in characters. +const TotalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB + +// ValidateAnnotations validates that a set of annotations are correctly defined. +func ValidateAnnotations(annotations map[string]string, path string) error { + errs := []error{} + for k := range annotations { + // The rule is QualifiedName except that case doesn't matter, so convert to lowercase before checking. + for _, msg := range IsQualifiedName(strings.ToLower(k)) { + errs = append(errs, fmt.Errorf("%v.%v is invalid: %v", path, k, msg)) + } + } + if err := ValidateAnnotationsSize(annotations); err != nil { + errs = append(errs, fmt.Errorf("%v is too long: %v", path, err)) + } + return errors.Join(errs...) +} + +// ValidateAnnotationsSize validates that a set of annotations is not too large. +func ValidateAnnotationsSize(annotations map[string]string) error { + var totalSize int64 + for k, v := range annotations { + totalSize += (int64)(len(k)) + (int64)(len(v)) + } + if totalSize > (int64)(TotalAnnotationSizeLimitB) { + return fmt.Errorf("annotations size %d is larger than limit %d", totalSize, TotalAnnotationSizeLimitB) + } + return nil +} diff --git a/vendor/tags.cncf.io/container-device-interface/internal/validation/k8s/validation.go b/vendor/tags.cncf.io/container-device-interface/internal/validation/k8s/validation.go new file mode 100644 index 00000000..5ad6ce27 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/internal/validation/k8s/validation.go @@ -0,0 +1,217 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Adapted from k8s.io/apimachinery/pkg/util/validation: +// https://github.com/kubernetes/apimachinery/blob/7687996c715ee7d5c8cf1e3215e607eb065a4221/pkg/util/validation/validation.go + +package k8s + +import ( + "fmt" + "regexp" + "strings" +) + +const qnameCharFmt string = "[A-Za-z0-9]" +const qnameExtCharFmt string = "[-A-Za-z0-9_.]" +const qualifiedNameFmt string = "(" + qnameCharFmt + qnameExtCharFmt + "*)?" + qnameCharFmt +const qualifiedNameErrMsg string = "must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character" +const qualifiedNameMaxLength int = 63 + +var qualifiedNameRegexp = regexp.MustCompile("^" + qualifiedNameFmt + "$") + +// IsQualifiedName tests whether the value passed is what Kubernetes calls a +// "qualified name". This is a format used in various places throughout the +// system. If the value is not valid, a list of error strings is returned. +// Otherwise an empty list (or nil) is returned. +func IsQualifiedName(value string) []string { + var errs []string + parts := strings.Split(value, "/") + var name string + switch len(parts) { + case 1: + name = parts[0] + case 2: + var prefix string + prefix, name = parts[0], parts[1] + if len(prefix) == 0 { + errs = append(errs, "prefix part "+EmptyError()) + } else if msgs := IsDNS1123Subdomain(prefix); len(msgs) != 0 { + errs = append(errs, prefixEach(msgs, "prefix part ")...) + } + default: + return append(errs, "a qualified name "+RegexError(qualifiedNameErrMsg, qualifiedNameFmt, "MyName", "my.name", "123-abc")+ + " with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')") + } + + if len(name) == 0 { + errs = append(errs, "name part "+EmptyError()) + } else if len(name) > qualifiedNameMaxLength { + errs = append(errs, "name part "+MaxLenError(qualifiedNameMaxLength)) + } + if !qualifiedNameRegexp.MatchString(name) { + errs = append(errs, "name part "+RegexError(qualifiedNameErrMsg, qualifiedNameFmt, "MyName", "my.name", "123-abc")) + } + return errs +} + +const labelValueFmt string = "(" + qualifiedNameFmt + ")?" +const labelValueErrMsg string = "a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character" + +// LabelValueMaxLength is a label's max length +const LabelValueMaxLength int = 63 + +var labelValueRegexp = regexp.MustCompile("^" + labelValueFmt + "$") + +// IsValidLabelValue tests whether the value passed is a valid label value. If +// the value is not valid, a list of error strings is returned. Otherwise an +// empty list (or nil) is returned. +func IsValidLabelValue(value string) []string { + var errs []string + if len(value) > LabelValueMaxLength { + errs = append(errs, MaxLenError(LabelValueMaxLength)) + } + if !labelValueRegexp.MatchString(value) { + errs = append(errs, RegexError(labelValueErrMsg, labelValueFmt, "MyValue", "my_value", "12345")) + } + return errs +} + +const dns1123LabelFmt string = "[a-z0-9]([-a-z0-9]*[a-z0-9])?" +const dns1123LabelErrMsg string = "a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character" + +// DNS1123LabelMaxLength is a label's max length in DNS (RFC 1123) +const DNS1123LabelMaxLength int = 63 + +var dns1123LabelRegexp = regexp.MustCompile("^" + dns1123LabelFmt + "$") + +// IsDNS1123Label tests for a string that conforms to the definition of a label in +// DNS (RFC 1123). +func IsDNS1123Label(value string) []string { + var errs []string + if len(value) > DNS1123LabelMaxLength { + errs = append(errs, MaxLenError(DNS1123LabelMaxLength)) + } + if !dns1123LabelRegexp.MatchString(value) { + errs = append(errs, RegexError(dns1123LabelErrMsg, dns1123LabelFmt, "my-name", "123-abc")) + } + return errs +} + +const dns1123SubdomainFmt string = dns1123LabelFmt + "(\\." + dns1123LabelFmt + ")*" +const dns1123SubdomainErrorMsg string = "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character" + +// DNS1123SubdomainMaxLength is a subdomain's max length in DNS (RFC 1123) +const DNS1123SubdomainMaxLength int = 253 + +var dns1123SubdomainRegexp = regexp.MustCompile("^" + dns1123SubdomainFmt + "$") + +// IsDNS1123Subdomain tests for a string that conforms to the definition of a +// subdomain in DNS (RFC 1123). +func IsDNS1123Subdomain(value string) []string { + var errs []string + if len(value) > DNS1123SubdomainMaxLength { + errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength)) + } + if !dns1123SubdomainRegexp.MatchString(value) { + errs = append(errs, RegexError(dns1123SubdomainErrorMsg, dns1123SubdomainFmt, "example.com")) + } + return errs +} + +const dns1035LabelFmt string = "[a-z]([-a-z0-9]*[a-z0-9])?" +const dns1035LabelErrMsg string = "a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character" + +// DNS1035LabelMaxLength is a label's max length in DNS (RFC 1035) +const DNS1035LabelMaxLength int = 63 + +var dns1035LabelRegexp = regexp.MustCompile("^" + dns1035LabelFmt + "$") + +// IsDNS1035Label tests for a string that conforms to the definition of a label in +// DNS (RFC 1035). +func IsDNS1035Label(value string) []string { + var errs []string + if len(value) > DNS1035LabelMaxLength { + errs = append(errs, MaxLenError(DNS1035LabelMaxLength)) + } + if !dns1035LabelRegexp.MatchString(value) { + errs = append(errs, RegexError(dns1035LabelErrMsg, dns1035LabelFmt, "my-name", "abc-123")) + } + return errs +} + +// wildcard definition - RFC 1034 section 4.3.3. +// examples: +// - valid: *.bar.com, *.foo.bar.com +// - invalid: *.*.bar.com, *.foo.*.com, *bar.com, f*.bar.com, * +const wildcardDNS1123SubdomainFmt = "\\*\\." + dns1123SubdomainFmt +const wildcardDNS1123SubdomainErrMsg = "a wildcard DNS-1123 subdomain must start with '*.', followed by a valid DNS subdomain, which must consist of lower case alphanumeric characters, '-' or '.' and end with an alphanumeric character" + +// IsWildcardDNS1123Subdomain tests for a string that conforms to the definition of a +// wildcard subdomain in DNS (RFC 1034 section 4.3.3). +func IsWildcardDNS1123Subdomain(value string) []string { + wildcardDNS1123SubdomainRegexp := regexp.MustCompile("^" + wildcardDNS1123SubdomainFmt + "$") + + var errs []string + if len(value) > DNS1123SubdomainMaxLength { + errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength)) + } + if !wildcardDNS1123SubdomainRegexp.MatchString(value) { + errs = append(errs, RegexError(wildcardDNS1123SubdomainErrMsg, wildcardDNS1123SubdomainFmt, "*.example.com")) + } + return errs +} + +// MaxLenError returns a string explanation of a "string too long" validation +// failure. +func MaxLenError(length int) string { + return fmt.Sprintf("must be no more than %d characters", length) +} + +// RegexError returns a string explanation of a regex validation failure. +func RegexError(msg string, fmt string, examples ...string) string { + if len(examples) == 0 { + return msg + " (regex used for validation is '" + fmt + "')" + } + msg += " (e.g. " + for i := range examples { + if i > 0 { + msg += " or " + } + msg += "'" + examples[i] + "', " + } + msg += "regex used for validation is '" + fmt + "')" + return msg +} + +// EmptyError returns a string explanation of a "must not be empty" validation +// failure. +func EmptyError() string { + return "must be non-empty" +} + +func prefixEach(msgs []string, prefix string) []string { + for i := range msgs { + msgs[i] = prefix + msgs[i] + } + return msgs +} + +// InclusiveRangeError returns a string explanation of a numeric "must be +// between" validation failure. +func InclusiveRangeError(lo, hi int) string { + return fmt.Sprintf(`must be between %d and %d, inclusive`, lo, hi) +} diff --git a/vendor/tags.cncf.io/container-device-interface/internal/validation/validate.go b/vendor/tags.cncf.io/container-device-interface/internal/validation/validate.go new file mode 100644 index 00000000..5d9b55ff --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/internal/validation/validate.go @@ -0,0 +1,56 @@ +/* + Copyright © The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package validation + +import ( + "fmt" + "strings" + + "tags.cncf.io/container-device-interface/internal/validation/k8s" +) + +// ValidateSpecAnnotations checks whether spec annotations are valid. +func ValidateSpecAnnotations(name string, any interface{}) error { + if any == nil { + return nil + } + + switch v := any.(type) { + case map[string]interface{}: + annotations := make(map[string]string) + for k, v := range v { + if s, ok := v.(string); ok { + annotations[k] = s + } else { + return fmt.Errorf("invalid annotation %v.%v; %v is not a string", name, k, any) + } + } + return validateSpecAnnotations(name, annotations) + } + + return nil +} + +// validateSpecAnnotations checks whether spec annotations are valid. +func validateSpecAnnotations(name string, annotations map[string]string) error { + path := "annotations" + if name != "" { + path = strings.Join([]string{name, path}, ".") + } + + return k8s.ValidateAnnotations(annotations, path) +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/annotations.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/annotations.go new file mode 100644 index 00000000..a596c610 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/annotations.go @@ -0,0 +1,141 @@ +/* + Copyright © 2021-2022 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import ( + "errors" + "fmt" + "strings" + + "tags.cncf.io/container-device-interface/pkg/parser" +) + +const ( + // AnnotationPrefix is the prefix for CDI container annotation keys. + AnnotationPrefix = "cdi.k8s.io/" +) + +// UpdateAnnotations updates annotations with a plugin-specific CDI device +// injection request for the given devices. Upon any error a non-nil error +// is returned and annotations are left intact. By convention plugin should +// be in the format of "vendor.device-type". +func UpdateAnnotations(annotations map[string]string, plugin string, deviceID string, devices []string) (map[string]string, error) { + key, err := AnnotationKey(plugin, deviceID) + if err != nil { + return annotations, fmt.Errorf("CDI annotation failed: %w", err) + } + if _, ok := annotations[key]; ok { + return annotations, fmt.Errorf("CDI annotation failed, key %q used", key) + } + value, err := AnnotationValue(devices) + if err != nil { + return annotations, fmt.Errorf("CDI annotation failed: %w", err) + } + + if annotations == nil { + annotations = make(map[string]string) + } + annotations[key] = value + + return annotations, nil +} + +// ParseAnnotations parses annotations for CDI device injection requests. +// The keys and devices from all such requests are collected into slices +// which are returned as the result. All devices are expected to be fully +// qualified CDI device names. If any device fails this check empty slices +// are returned along with a non-nil error. The annotations are expected +// to be formatted by, or in a compatible fashion to UpdateAnnotations(). +func ParseAnnotations(annotations map[string]string) ([]string, []string, error) { + var ( + keys []string + devices []string + ) + + for key, value := range annotations { + if !strings.HasPrefix(key, AnnotationPrefix) { + continue + } + for _, d := range strings.Split(value, ",") { + if !parser.IsQualifiedName(d) { + return nil, nil, fmt.Errorf("invalid CDI device name %q", d) + } + devices = append(devices, d) + } + keys = append(keys, key) + } + + return keys, devices, nil +} + +// AnnotationKey returns a unique annotation key for an device allocation +// by a K8s device plugin. pluginName should be in the format of +// "vendor.device-type". deviceID is the ID of the device the plugin is +// allocating. It is used to make sure that the generated key is unique +// even if multiple allocations by a single plugin needs to be annotated. +func AnnotationKey(pluginName, deviceID string) (string, error) { + const maxNameLen = 63 + + if pluginName == "" { + return "", errors.New("invalid plugin name, empty") + } + if deviceID == "" { + return "", errors.New("invalid deviceID, empty") + } + + name := pluginName + "_" + strings.ReplaceAll(deviceID, "/", "_") + + if len(name) > maxNameLen { + return "", fmt.Errorf("invalid plugin+deviceID %q, too long", name) + } + + if c := rune(name[0]); !parser.IsAlphaNumeric(c) { + return "", fmt.Errorf("invalid name %q, first '%c' should be alphanumeric", + name, c) + } + if len(name) > 2 { + for _, c := range name[1 : len(name)-1] { + switch { + case parser.IsAlphaNumeric(c): + case c == '_' || c == '-' || c == '.': + default: + return "", fmt.Errorf("invalid name %q, invalid character '%c'", + name, c) + } + } + } + if c := rune(name[len(name)-1]); !parser.IsAlphaNumeric(c) { + return "", fmt.Errorf("invalid name %q, last '%c' should be alphanumeric", + name, c) + } + + return AnnotationPrefix + name, nil +} + +// AnnotationValue returns an annotation value for the given devices. +func AnnotationValue(devices []string) (string, error) { + value, sep := "", "" + for _, d := range devices { + if _, _, _, err := parser.ParseQualifiedName(d); err != nil { + return "", err + } + value += sep + d + sep = "," + } + + return value, nil +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go new file mode 100644 index 00000000..7095f27d --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go @@ -0,0 +1,613 @@ +/* + Copyright © 2021 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import ( + "errors" + "fmt" + "io/fs" + "os" + "path/filepath" + "runtime" + "sort" + "strings" + "sync" + + "github.com/fsnotify/fsnotify" + oci "github.com/opencontainers/runtime-spec/specs-go" + cdi "tags.cncf.io/container-device-interface/specs-go" +) + +// Option is an option to change some aspect of default CDI behavior. +type Option func(*Cache) + +// Cache stores CDI Specs loaded from Spec directories. +type Cache struct { + sync.Mutex + specDirs []string + specs map[string][]*Spec + devices map[string]*Device + errors map[string][]error + dirErrors map[string]error + + autoRefresh bool + watch *watch +} + +// WithAutoRefresh returns an option to control automatic Cache refresh. +// By default, auto-refresh is enabled, the list of Spec directories are +// monitored and the Cache is automatically refreshed whenever a change +// is detected. This option can be used to disable this behavior when a +// manually refreshed mode is preferable. +func WithAutoRefresh(autoRefresh bool) Option { + return func(c *Cache) { + c.autoRefresh = autoRefresh + } +} + +// NewCache creates a new CDI Cache. The cache is populated from a set +// of CDI Spec directories. These can be specified using a WithSpecDirs +// option. The default set of directories is exposed in DefaultSpecDirs. +// +// Note: +// +// The error returned by this function is always nil and it is only +// returned to maintain API compatibility with consumers. +func NewCache(options ...Option) (*Cache, error) { + return newCache(options...), nil +} + +// newCache creates a CDI cache with the supplied options. +// This function allows testing without handling the nil error returned by the +// NewCache function. +func newCache(options ...Option) *Cache { + c := &Cache{ + autoRefresh: true, + watch: &watch{}, + } + + WithSpecDirs(DefaultSpecDirs...)(c) + c.Lock() + defer c.Unlock() + + c.configure(options...) + return c +} + +// Configure applies options to the Cache. Updates and refreshes the +// Cache if options have changed. +func (c *Cache) Configure(options ...Option) error { + if len(options) == 0 { + return nil + } + + c.Lock() + defer c.Unlock() + + c.configure(options...) + + return nil +} + +// Configure the Cache. Start/stop CDI Spec directory watch, refresh +// the Cache if necessary. +func (c *Cache) configure(options ...Option) { + for _, o := range options { + o(c) + } + + c.dirErrors = make(map[string]error) + + c.watch.stop() + if c.autoRefresh { + c.watch.setup(c.specDirs, c.dirErrors) + c.watch.start(&c.Mutex, c.refresh, c.dirErrors) + } + _ = c.refresh() // we record but ignore errors +} + +// Refresh rescans the CDI Spec directories and refreshes the Cache. +// In manual refresh mode the cache is always refreshed. In auto- +// refresh mode the cache is only refreshed if it is out of date. +func (c *Cache) Refresh() error { + c.Lock() + defer c.Unlock() + + // force a refresh in manual mode + if refreshed, err := c.refreshIfRequired(!c.autoRefresh); refreshed { + return err + } + + // collect and return cached errors, much like refresh() does it + errs := []error{} + for _, specErrs := range c.errors { + errs = append(errs, errors.Join(specErrs...)) + } + return errors.Join(errs...) +} + +// Refresh the Cache by rescanning CDI Spec directories and files. +func (c *Cache) refresh() error { + var ( + specs = map[string][]*Spec{} + devices = map[string]*Device{} + conflicts = map[string]struct{}{} + specErrors = map[string][]error{} + ) + + // collect errors per spec file path and once globally + collectError := func(err error, paths ...string) { + for _, path := range paths { + specErrors[path] = append(specErrors[path], err) + } + } + // resolve conflicts based on device Spec priority (order of precedence) + resolveConflict := func(name string, dev *Device, old *Device) bool { + devSpec, oldSpec := dev.GetSpec(), old.GetSpec() + devPrio, oldPrio := devSpec.GetPriority(), oldSpec.GetPriority() + switch { + case devPrio > oldPrio: + return false + case devPrio == oldPrio: + devPath, oldPath := devSpec.GetPath(), oldSpec.GetPath() + collectError(fmt.Errorf("conflicting device %q (specs %q, %q)", + name, devPath, oldPath), devPath, oldPath) + conflicts[name] = struct{}{} + } + return true + } + + _ = scanSpecDirs(c.specDirs, func(path string, priority int, spec *Spec, err error) error { + path = filepath.Clean(path) + if err != nil { + collectError(fmt.Errorf("failed to load CDI Spec %w", err), path) + return nil + } + + vendor := spec.GetVendor() + specs[vendor] = append(specs[vendor], spec) + + for _, dev := range spec.devices { + qualified := dev.GetQualifiedName() + other, ok := devices[qualified] + if ok { + if resolveConflict(qualified, dev, other) { + continue + } + } + devices[qualified] = dev + } + + return nil + }) + + for conflict := range conflicts { + delete(devices, conflict) + } + + c.specs = specs + c.devices = devices + c.errors = specErrors + + errs := []error{} + for _, specErrs := range specErrors { + errs = append(errs, errors.Join(specErrs...)) + } + return errors.Join(errs...) +} + +// RefreshIfRequired triggers a refresh if necessary. +func (c *Cache) refreshIfRequired(force bool) (bool, error) { + // We need to refresh if + // - it's forced by an explicit call to Refresh() in manual mode + // - a missing Spec dir appears (added to watch) in auto-refresh mode + if force || (c.autoRefresh && c.watch.update(c.dirErrors)) { + return true, c.refresh() + } + return false, nil +} + +// InjectDevices injects the given qualified devices to an OCI Spec. It +// returns any unresolvable devices and an error if injection fails for +// any of the devices. Might trigger a cache refresh, in which case any +// errors encountered can be obtained using GetErrors(). +func (c *Cache) InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, error) { + var unresolved []string + + if ociSpec == nil { + return devices, fmt.Errorf("can't inject devices, nil OCI Spec") + } + + c.Lock() + defer c.Unlock() + + _, _ = c.refreshIfRequired(false) // we record but ignore errors + + edits := &ContainerEdits{} + specs := map[*Spec]struct{}{} + + for _, device := range devices { + d := c.devices[device] + if d == nil { + unresolved = append(unresolved, device) + continue + } + if _, ok := specs[d.GetSpec()]; !ok { + specs[d.GetSpec()] = struct{}{} + edits.Append(d.GetSpec().edits()) + } + edits.Append(d.edits()) + } + + if unresolved != nil { + return unresolved, fmt.Errorf("unresolvable CDI devices %s", + strings.Join(unresolved, ", ")) + } + + if err := edits.Apply(ociSpec); err != nil { + return nil, fmt.Errorf("failed to inject devices: %w", err) + } + + return nil, nil +} + +// highestPrioritySpecDir returns the Spec directory with highest priority +// and its priority. +func (c *Cache) highestPrioritySpecDir() (string, int) { + if len(c.specDirs) == 0 { + return "", -1 + } + + prio := len(c.specDirs) - 1 + dir := c.specDirs[prio] + + return dir, prio +} + +// WriteSpec writes a Spec file with the given content into the highest +// priority Spec directory. If name has a "json" or "yaml" extension it +// choses the encoding. Otherwise the default YAML encoding is used. +func (c *Cache) WriteSpec(raw *cdi.Spec, name string) error { + var ( + specDir string + path string + prio int + spec *Spec + err error + ) + + specDir, prio = c.highestPrioritySpecDir() + if specDir == "" { + return errors.New("no Spec directories to write to") + } + + path = filepath.Join(specDir, name) + if ext := filepath.Ext(path); ext != ".json" && ext != ".yaml" { + path += defaultSpecExt + } + + spec, err = newSpec(raw, path, prio) + if err != nil { + return err + } + + return spec.write(true) +} + +// RemoveSpec removes a Spec with the given name from the highest +// priority Spec directory. This function can be used to remove a +// Spec previously written by WriteSpec(). If the file exists and +// its removal fails RemoveSpec returns an error. +func (c *Cache) RemoveSpec(name string) error { + var ( + specDir string + path string + err error + ) + + specDir, _ = c.highestPrioritySpecDir() + if specDir == "" { + return errors.New("no Spec directories to remove from") + } + + path = filepath.Join(specDir, name) + if ext := filepath.Ext(path); ext != ".json" && ext != ".yaml" { + path += defaultSpecExt + } + + err = os.Remove(path) + if err != nil && errors.Is(err, fs.ErrNotExist) { + err = nil + } + + return err +} + +// GetDevice returns the cached device for the given qualified name. Might trigger +// a cache refresh, in which case any errors encountered can be obtained using +// GetErrors(). +func (c *Cache) GetDevice(device string) *Device { + c.Lock() + defer c.Unlock() + + _, _ = c.refreshIfRequired(false) // we record but ignore errors + + return c.devices[device] +} + +// ListDevices lists all cached devices by qualified name. Might trigger a cache +// refresh, in which case any errors encountered can be obtained using GetErrors(). +func (c *Cache) ListDevices() []string { + var devices []string + + c.Lock() + defer c.Unlock() + + _, _ = c.refreshIfRequired(false) // we record but ignore errors + + for name := range c.devices { + devices = append(devices, name) + } + sort.Strings(devices) + + return devices +} + +// ListVendors lists all vendors known to the cache. Might trigger a cache refresh, +// in which case any errors encountered can be obtained using GetErrors(). +func (c *Cache) ListVendors() []string { + var vendors []string + + c.Lock() + defer c.Unlock() + + _, _ = c.refreshIfRequired(false) // we record but ignore errors + + for vendor := range c.specs { + vendors = append(vendors, vendor) + } + sort.Strings(vendors) + + return vendors +} + +// ListClasses lists all device classes known to the cache. Might trigger a cache +// refresh, in which case any errors encountered can be obtained using GetErrors(). +func (c *Cache) ListClasses() []string { + var ( + cmap = map[string]struct{}{} + classes []string + ) + + c.Lock() + defer c.Unlock() + + _, _ = c.refreshIfRequired(false) // we record but ignore errors + + for _, specs := range c.specs { + for _, spec := range specs { + cmap[spec.GetClass()] = struct{}{} + } + } + for class := range cmap { + classes = append(classes, class) + } + sort.Strings(classes) + + return classes +} + +// GetVendorSpecs returns all specs for the given vendor. Might trigger a cache +// refresh, in which case any errors encountered can be obtained using GetErrors(). +func (c *Cache) GetVendorSpecs(vendor string) []*Spec { + c.Lock() + defer c.Unlock() + + _, _ = c.refreshIfRequired(false) // we record but ignore errors + + return c.specs[vendor] +} + +// GetSpecErrors returns all errors encountered for the spec during the +// last cache refresh. +func (c *Cache) GetSpecErrors(spec *Spec) []error { + var errors []error + + c.Lock() + defer c.Unlock() + + if errs, ok := c.errors[spec.GetPath()]; ok { + errors = make([]error, len(errs)) + copy(errors, errs) + } + + return errors +} + +// GetErrors returns all errors encountered during the last +// cache refresh. +func (c *Cache) GetErrors() map[string][]error { + c.Lock() + defer c.Unlock() + + errors := map[string][]error{} + for path, errs := range c.errors { + errors[path] = errs + } + for path, err := range c.dirErrors { + errors[path] = []error{err} + } + + return errors +} + +// GetSpecDirectories returns the CDI Spec directories currently in use. +func (c *Cache) GetSpecDirectories() []string { + c.Lock() + defer c.Unlock() + + dirs := make([]string, len(c.specDirs)) + copy(dirs, c.specDirs) + return dirs +} + +// GetSpecDirErrors returns any errors related to configured Spec directories. +func (c *Cache) GetSpecDirErrors() map[string]error { + if c.dirErrors == nil { + return nil + } + + c.Lock() + defer c.Unlock() + + errors := make(map[string]error) + for dir, err := range c.dirErrors { + errors[dir] = err + } + return errors +} + +// Our fsnotify helper wrapper. +type watch struct { + watcher *fsnotify.Watcher + tracked map[string]bool +} + +// Setup monitoring for the given Spec directories. +func (w *watch) setup(dirs []string, dirErrors map[string]error) { + var ( + dir string + err error + ) + w.tracked = make(map[string]bool) + for _, dir = range dirs { + w.tracked[dir] = false + } + + w.watcher, err = fsnotify.NewWatcher() + if err != nil { + for _, dir := range dirs { + dirErrors[dir] = fmt.Errorf("failed to create watcher: %w", err) + } + return + } + + w.update(dirErrors) +} + +// Start watching Spec directories for relevant changes. +func (w *watch) start(m *sync.Mutex, refresh func() error, dirErrors map[string]error) { + go w.watch(w.watcher, m, refresh, dirErrors) +} + +// Stop watching directories. +func (w *watch) stop() { + if w.watcher == nil { + return + } + + w.watcher.Close() + w.tracked = nil +} + +// Watch Spec directory changes, triggering a refresh if necessary. +func (w *watch) watch(fsw *fsnotify.Watcher, m *sync.Mutex, refresh func() error, dirErrors map[string]error) { + watch := fsw + if watch == nil { + return + } + + eventMask := fsnotify.Rename | fsnotify.Remove | fsnotify.Write + // On macOS, we also need to watch for Create events. + if runtime.GOOS == "darwin" { + eventMask |= fsnotify.Create + } + + for { + select { + case event, ok := <-watch.Events: + if !ok { + return + } + + if (event.Op & eventMask) == 0 { + continue + } + if event.Op == fsnotify.Write || event.Op == fsnotify.Create { + if ext := filepath.Ext(event.Name); ext != ".json" && ext != ".yaml" { + continue + } + } + + m.Lock() + if event.Op == fsnotify.Remove && w.tracked[event.Name] { + w.update(dirErrors, event.Name) + } else { + w.update(dirErrors) + } + _ = refresh() + m.Unlock() + + case _, ok := <-watch.Errors: + if !ok { + return + } + } + } +} + +// Update watch with pending/missing or removed directories. +func (w *watch) update(dirErrors map[string]error, removed ...string) bool { + var ( + dir string + ok bool + err error + update bool + ) + + // If we failed to create an fsnotify.Watcher we have a nil watcher here + // (but with autoRefresh left on). One known case when this can happen is + // if we have too many open files. In that case we always return true and + // force a refresh. + if w.watcher == nil { + return true + } + + for dir, ok = range w.tracked { + if ok { + continue + } + + err = w.watcher.Add(dir) + if err == nil { + w.tracked[dir] = true + delete(dirErrors, dir) + update = true + } else { + w.tracked[dir] = false + dirErrors[dir] = fmt.Errorf("failed to monitor for changes: %w", err) + } + } + + for _, dir = range removed { + w.tracked[dir] = false + dirErrors[dir] = errors.New("directory removed") + update = true + } + + return update +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_darwin.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_darwin.go new file mode 100644 index 00000000..b09ea6ff --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_darwin.go @@ -0,0 +1,26 @@ +//go:build darwin +// +build darwin + +/* + Copyright © 2021 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import "syscall" + +func osSync() { + _ = syscall.Sync() +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_unix.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_unix.go new file mode 100644 index 00000000..b7c44129 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_unix.go @@ -0,0 +1,26 @@ +//go:build !windows && !darwin +// +build !windows,!darwin + +/* + Copyright © 2021 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import "syscall" + +func osSync() { + syscall.Sync() +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_windows.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_windows.go new file mode 100644 index 00000000..c6dabf5f --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_windows.go @@ -0,0 +1,22 @@ +//go:build windows +// +build windows + +/* + Copyright © 2021 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +func osSync() {} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits.go new file mode 100644 index 00000000..4744eff8 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits.go @@ -0,0 +1,389 @@ +/* + Copyright © 2021 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + oci "github.com/opencontainers/runtime-spec/specs-go" + ocigen "github.com/opencontainers/runtime-tools/generate" + cdi "tags.cncf.io/container-device-interface/specs-go" +) + +const ( + // PrestartHook is the name of the OCI "prestart" hook. + PrestartHook = "prestart" + // CreateRuntimeHook is the name of the OCI "createRuntime" hook. + CreateRuntimeHook = "createRuntime" + // CreateContainerHook is the name of the OCI "createContainer" hook. + CreateContainerHook = "createContainer" + // StartContainerHook is the name of the OCI "startContainer" hook. + StartContainerHook = "startContainer" + // PoststartHook is the name of the OCI "poststart" hook. + PoststartHook = "poststart" + // PoststopHook is the name of the OCI "poststop" hook. + PoststopHook = "poststop" +) + +var ( + // Names of recognized hooks. + validHookNames = map[string]struct{}{ + PrestartHook: {}, + CreateRuntimeHook: {}, + CreateContainerHook: {}, + StartContainerHook: {}, + PoststartHook: {}, + PoststopHook: {}, + } +) + +// ContainerEdits represent updates to be applied to an OCI Spec. +// These updates can be specific to a CDI device, or they can be +// specific to a CDI Spec. In the former case these edits should +// be applied to all OCI Specs where the corresponding CDI device +// is injected. In the latter case, these edits should be applied +// to all OCI Specs where at least one devices from the CDI Spec +// is injected. +type ContainerEdits struct { + *cdi.ContainerEdits +} + +// Apply edits to the given OCI Spec. Updates the OCI Spec in place. +// Returns an error if the update fails. +func (e *ContainerEdits) Apply(spec *oci.Spec) error { + if spec == nil { + return errors.New("can't edit nil OCI Spec") + } + if e == nil || e.ContainerEdits == nil { + return nil + } + + specgen := ocigen.NewFromSpec(spec) + if len(e.Env) > 0 { + specgen.AddMultipleProcessEnv(e.Env) + } + + for _, d := range e.DeviceNodes { + dn := DeviceNode{d} + + err := dn.fillMissingInfo() + if err != nil { + return err + } + dev := dn.toOCI() + if dev.UID == nil && spec.Process != nil { + if uid := spec.Process.User.UID; uid > 0 { + dev.UID = &uid + } + } + if dev.GID == nil && spec.Process != nil { + if gid := spec.Process.User.GID; gid > 0 { + dev.GID = &gid + } + } + + specgen.RemoveDevice(dev.Path) + specgen.AddDevice(dev) + + if dev.Type == "b" || dev.Type == "c" { + access := d.Permissions + if access == "" { + access = "rwm" + } + specgen.AddLinuxResourcesDevice(true, dev.Type, &dev.Major, &dev.Minor, access) + } + } + + if len(e.Mounts) > 0 { + for _, m := range e.Mounts { + specgen.RemoveMount(m.ContainerPath) + specgen.AddMount((&Mount{m}).toOCI()) + } + sortMounts(&specgen) + } + + for _, h := range e.Hooks { + ociHook := (&Hook{h}).toOCI() + switch h.HookName { + case PrestartHook: + specgen.AddPreStartHook(ociHook) + case PoststartHook: + specgen.AddPostStartHook(ociHook) + case PoststopHook: + specgen.AddPostStopHook(ociHook) + // TODO: Maybe runtime-tools/generate should be updated with these... + case CreateRuntimeHook: + ensureOCIHooks(spec) + spec.Hooks.CreateRuntime = append(spec.Hooks.CreateRuntime, ociHook) + case CreateContainerHook: + ensureOCIHooks(spec) + spec.Hooks.CreateContainer = append(spec.Hooks.CreateContainer, ociHook) + case StartContainerHook: + ensureOCIHooks(spec) + spec.Hooks.StartContainer = append(spec.Hooks.StartContainer, ociHook) + default: + return fmt.Errorf("unknown hook name %q", h.HookName) + } + } + + if e.IntelRdt != nil { + // The specgen is missing functionality to set all parameters so we + // just piggy-back on it to initialize all structs and the copy over. + specgen.SetLinuxIntelRdtClosID(e.IntelRdt.ClosID) + spec.Linux.IntelRdt = (&IntelRdt{e.IntelRdt}).toOCI() + } + + for _, additionalGID := range e.AdditionalGIDs { + if additionalGID == 0 { + continue + } + specgen.AddProcessAdditionalGid(additionalGID) + } + + return nil +} + +// Validate container edits. +func (e *ContainerEdits) Validate() error { + if e == nil || e.ContainerEdits == nil { + return nil + } + + if err := ValidateEnv(e.Env); err != nil { + return fmt.Errorf("invalid container edits: %w", err) + } + for _, d := range e.DeviceNodes { + if err := (&DeviceNode{d}).Validate(); err != nil { + return err + } + } + for _, h := range e.Hooks { + if err := (&Hook{h}).Validate(); err != nil { + return err + } + } + for _, m := range e.Mounts { + if err := (&Mount{m}).Validate(); err != nil { + return err + } + } + if e.IntelRdt != nil { + if err := (&IntelRdt{e.IntelRdt}).Validate(); err != nil { + return err + } + } + + return nil +} + +// Append other edits into this one. If called with a nil receiver, +// allocates and returns newly allocated edits. +func (e *ContainerEdits) Append(o *ContainerEdits) *ContainerEdits { + if o == nil || o.ContainerEdits == nil { + return e + } + if e == nil { + e = &ContainerEdits{} + } + if e.ContainerEdits == nil { + e.ContainerEdits = &cdi.ContainerEdits{} + } + + e.Env = append(e.Env, o.Env...) + e.DeviceNodes = append(e.DeviceNodes, o.DeviceNodes...) + e.Hooks = append(e.Hooks, o.Hooks...) + e.Mounts = append(e.Mounts, o.Mounts...) + if o.IntelRdt != nil { + e.IntelRdt = o.IntelRdt + } + e.AdditionalGIDs = append(e.AdditionalGIDs, o.AdditionalGIDs...) + + return e +} + +// isEmpty returns true if these edits are empty. This is valid in a +// global Spec context but invalid in a Device context. +func (e *ContainerEdits) isEmpty() bool { + if e == nil { + return false + } + if len(e.Env) > 0 { + return false + } + if len(e.DeviceNodes) > 0 { + return false + } + if len(e.Hooks) > 0 { + return false + } + if len(e.Mounts) > 0 { + return false + } + if len(e.AdditionalGIDs) > 0 { + return false + } + if e.IntelRdt != nil { + return false + } + return true +} + +// ValidateEnv validates the given environment variables. +func ValidateEnv(env []string) error { + for _, v := range env { + if strings.IndexByte(v, byte('=')) <= 0 { + return fmt.Errorf("invalid environment variable %q", v) + } + } + return nil +} + +// DeviceNode is a CDI Spec DeviceNode wrapper, used for validating DeviceNodes. +type DeviceNode struct { + *cdi.DeviceNode +} + +// Validate a CDI Spec DeviceNode. +func (d *DeviceNode) Validate() error { + validTypes := map[string]struct{}{ + "": {}, + "b": {}, + "c": {}, + "u": {}, + "p": {}, + } + + if d.Path == "" { + return errors.New("invalid (empty) device path") + } + if _, ok := validTypes[d.Type]; !ok { + return fmt.Errorf("device %q: invalid type %q", d.Path, d.Type) + } + for _, bit := range d.Permissions { + if bit != 'r' && bit != 'w' && bit != 'm' { + return fmt.Errorf("device %q: invalid permissions %q", + d.Path, d.Permissions) + } + } + return nil +} + +// Hook is a CDI Spec Hook wrapper, used for validating hooks. +type Hook struct { + *cdi.Hook +} + +// Validate a hook. +func (h *Hook) Validate() error { + if _, ok := validHookNames[h.HookName]; !ok { + return fmt.Errorf("invalid hook name %q", h.HookName) + } + if h.Path == "" { + return fmt.Errorf("invalid hook %q with empty path", h.HookName) + } + if err := ValidateEnv(h.Env); err != nil { + return fmt.Errorf("invalid hook %q: %w", h.HookName, err) + } + return nil +} + +// Mount is a CDI Mount wrapper, used for validating mounts. +type Mount struct { + *cdi.Mount +} + +// Validate a mount. +func (m *Mount) Validate() error { + if m.HostPath == "" { + return errors.New("invalid mount, empty host path") + } + if m.ContainerPath == "" { + return errors.New("invalid mount, empty container path") + } + return nil +} + +// IntelRdt is a CDI IntelRdt wrapper. +// This is used for validation and conversion to OCI specifications. +type IntelRdt struct { + *cdi.IntelRdt +} + +// ValidateIntelRdt validates the IntelRdt configuration. +// +// Deprecated: ValidateIntelRdt is deprecated use IntelRdt.Validate() instead. +func ValidateIntelRdt(i *cdi.IntelRdt) error { + return (&IntelRdt{i}).Validate() +} + +// Validate validates the IntelRdt configuration. +func (i *IntelRdt) Validate() error { + // ClosID must be a valid Linux filename + if len(i.ClosID) >= 4096 || i.ClosID == "." || i.ClosID == ".." || strings.ContainsAny(i.ClosID, "/\n") { + return errors.New("invalid ClosID") + } + return nil +} + +// Ensure OCI Spec hooks are not nil so we can add hooks. +func ensureOCIHooks(spec *oci.Spec) { + if spec.Hooks == nil { + spec.Hooks = &oci.Hooks{} + } +} + +// sortMounts sorts the mounts in the given OCI Spec. +func sortMounts(specgen *ocigen.Generator) { + mounts := specgen.Mounts() + specgen.ClearMounts() + sort.Stable(orderedMounts(mounts)) + specgen.Config.Mounts = mounts +} + +// orderedMounts defines how to sort an OCI Spec Mount slice. +// This is the almost the same implementation sa used by CRI-O and Docker, +// with a minor tweak for stable sorting order (easier to test): +// +// https://github.com/moby/moby/blob/17.05.x/daemon/volumes.go#L26 +type orderedMounts []oci.Mount + +// Len returns the number of mounts. Used in sorting. +func (m orderedMounts) Len() int { + return len(m) +} + +// Less returns true if the number of parts (a/b/c would be 3 parts) in the +// mount indexed by parameter 1 is less than that of the mount indexed by +// parameter 2. Used in sorting. +func (m orderedMounts) Less(i, j int) bool { + return m.parts(i) < m.parts(j) +} + +// Swap swaps two items in an array of mounts. Used in sorting +func (m orderedMounts) Swap(i, j int) { + m[i], m[j] = m[j], m[i] +} + +// parts returns the number of parts in the destination of a mount. Used in sorting. +func (m orderedMounts) parts(i int) int { + return strings.Count(filepath.Clean(m[i].Destination), string(os.PathSeparator)) +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits_unix.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits_unix.go new file mode 100644 index 00000000..59977b21 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits_unix.go @@ -0,0 +1,88 @@ +//go:build !windows +// +build !windows + +/* + Copyright © 2021 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import ( + "errors" + "fmt" + + "golang.org/x/sys/unix" +) + +const ( + blockDevice = "b" + charDevice = "c" // or "u" + fifoDevice = "p" +) + +// deviceInfoFromPath takes the path to a device and returns its type, +// major and minor device numbers. +// +// It was adapted from https://github.com/opencontainers/runc/blob/v1.1.9/libcontainer/devices/device_unix.go#L30-L69 +func deviceInfoFromPath(path string) (devType string, major, minor int64, _ error) { + var stat unix.Stat_t + err := unix.Lstat(path, &stat) + if err != nil { + return "", 0, 0, err + } + switch stat.Mode & unix.S_IFMT { + case unix.S_IFBLK: + devType = blockDevice + case unix.S_IFCHR: + devType = charDevice + case unix.S_IFIFO: + devType = fifoDevice + default: + return "", 0, 0, errors.New("not a device node") + } + devNumber := uint64(stat.Rdev) //nolint:unconvert // Rdev is uint32 on e.g. MIPS. + return devType, int64(unix.Major(devNumber)), int64(unix.Minor(devNumber)), nil +} + +// fillMissingInfo fills in missing mandatory attributes from the host device. +func (d *DeviceNode) fillMissingInfo() error { + if d.HostPath == "" { + d.HostPath = d.Path + } + + if d.Type != "" && (d.Major != 0 || d.Type == "p") { + return nil + } + + deviceType, major, minor, err := deviceInfoFromPath(d.HostPath) + if err != nil { + return fmt.Errorf("failed to stat CDI host device %q: %w", d.HostPath, err) + } + + if d.Type == "" { + d.Type = deviceType + } else { + if d.Type != deviceType { + return fmt.Errorf("CDI device (%q, %q), host type mismatch (%s, %s)", + d.Path, d.HostPath, d.Type, deviceType) + } + } + if d.Major == 0 && d.Type != "p" { + d.Major = major + d.Minor = minor + } + + return nil +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits_windows.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits_windows.go new file mode 100644 index 00000000..fd91afa9 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits_windows.go @@ -0,0 +1,27 @@ +//go:build windows +// +build windows + +/* + Copyright © 2021 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import "fmt" + +// fillMissingInfo fills in missing mandatory attributes from the host device. +func (d *DeviceNode) fillMissingInfo() error { + return fmt.Errorf("unimplemented") +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/default-cache.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/default-cache.go new file mode 100644 index 00000000..7886ee51 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/default-cache.go @@ -0,0 +1,70 @@ +/* + Copyright © 2024 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import ( + "sync" + + oci "github.com/opencontainers/runtime-spec/specs-go" +) + +var ( + defaultCache *Cache + getDefaultOnce sync.Once +) + +func getOrCreateDefaultCache(options ...Option) (*Cache, bool) { + var created bool + getDefaultOnce.Do(func() { + defaultCache = newCache(options...) + created = true + }) + return defaultCache, created +} + +// GetDefaultCache returns the default CDI cache instance. +func GetDefaultCache() *Cache { + cache, _ := getOrCreateDefaultCache() + return cache +} + +// Configure applies options to the default CDI cache. Updates and refreshes +// the default cache if options are not empty. +func Configure(options ...Option) error { + cache, created := getOrCreateDefaultCache(options...) + if len(options) == 0 || created { + return nil + } + return cache.Configure(options...) +} + +// Refresh explicitly refreshes the default CDI cache instance. +func Refresh() error { + return GetDefaultCache().Refresh() +} + +// InjectDevices injects the given qualified devices to the given OCI Spec. +// using the default CDI cache instance to resolve devices. +func InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, error) { + return GetDefaultCache().InjectDevices(ociSpec, devices...) +} + +// GetErrors returns all errors encountered during the last refresh of +// the default CDI cache instance. +func GetErrors() map[string][]error { + return GetDefaultCache().GetErrors() +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/device.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/device.go new file mode 100644 index 00000000..2e5fa57f --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/device.go @@ -0,0 +1,88 @@ +/* + Copyright © 2021 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import ( + "fmt" + + oci "github.com/opencontainers/runtime-spec/specs-go" + "tags.cncf.io/container-device-interface/internal/validation" + "tags.cncf.io/container-device-interface/pkg/parser" + cdi "tags.cncf.io/container-device-interface/specs-go" +) + +// Device represents a CDI device of a Spec. +type Device struct { + *cdi.Device + spec *Spec +} + +// Create a new Device, associate it with the given Spec. +func newDevice(spec *Spec, d cdi.Device) (*Device, error) { + dev := &Device{ + Device: &d, + spec: spec, + } + + if err := dev.validate(); err != nil { + return nil, err + } + + return dev, nil +} + +// GetSpec returns the Spec this device is defined in. +func (d *Device) GetSpec() *Spec { + return d.spec +} + +// GetQualifiedName returns the qualified name for this device. +func (d *Device) GetQualifiedName() string { + return parser.QualifiedName(d.spec.GetVendor(), d.spec.GetClass(), d.Name) +} + +// ApplyEdits applies the device-speific container edits to an OCI Spec. +func (d *Device) ApplyEdits(ociSpec *oci.Spec) error { + return d.edits().Apply(ociSpec) +} + +// edits returns the applicable container edits for this spec. +func (d *Device) edits() *ContainerEdits { + return &ContainerEdits{&d.ContainerEdits} +} + +// Validate the device. +func (d *Device) validate() error { + if err := parser.ValidateDeviceName(d.Name); err != nil { + return err + } + name := d.Name + if d.spec != nil { + name = d.GetQualifiedName() + } + if err := validation.ValidateSpecAnnotations(name, d.Annotations); err != nil { + return err + } + edits := d.edits() + if edits.isEmpty() { + return fmt.Errorf("invalid device, empty device edits") + } + if err := edits.Validate(); err != nil { + return fmt.Errorf("invalid device %q: %w", d.Name, err) + } + return nil +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/doc.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/doc.go new file mode 100644 index 00000000..d00e0d33 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/doc.go @@ -0,0 +1,277 @@ +// Package cdi has the primary purpose of providing an API for +// interacting with CDI and consuming CDI devices. +// +// For more information about Container Device Interface, please refer to +// https://tags.cncf.io/container-device-interface +// +// # Container Device Interface +// +// Container Device Interface, or CDI for short, provides comprehensive +// third party device support for container runtimes. CDI uses vendor +// provided specification files, CDI Specs for short, to describe how a +// container's runtime environment should be modified when one or more +// of the vendor-specific devices is injected into the container. Beyond +// describing the low level platform-specific details of how to gain +// basic access to a device, CDI Specs allow more fine-grained device +// initialization, and the automatic injection of any necessary vendor- +// or device-specific software that might be required for a container +// to use a device or take full advantage of it. +// +// In the CDI device model containers request access to a device using +// fully qualified device names, qualified names for short, consisting of +// a vendor identifier, a device class and a device name or identifier. +// These pieces of information together uniquely identify a device among +// all device vendors, classes and device instances. +// +// This package implements an API for easy consumption of CDI. The API +// implements discovery, loading and caching of CDI Specs and injection +// of CDI devices into containers. This is the most common functionality +// the vast majority of CDI consumers need. The API should be usable both +// by OCI runtime clients and runtime implementations. +// +// # Default CDI Cache +// +// There is a default CDI cache instance which is always implicitly +// available and instantiated the first time it is referenced directly +// or indirectly. The most frequently used cache functions are available +// as identically named package level functions which operate on the +// default cache instance. +// +// # Device Injection +// +// Using the Cache one can inject CDI devices into a container with code +// similar to the following snippet: +// +// import ( +// "fmt" +// "strings" +// +// log "github.com/sirupsen/logrus" +// +// "tags.cncf.io/container-device-interface/pkg/cdi" +// "github.com/opencontainers/runtime-spec/specs-go" +// ) +// +// func injectCDIDevices(spec *specs.Spec, devices []string) error { +// log.Debug("pristine OCI Spec: %s", dumpSpec(spec)) +// +// cache := cdi.GetDefaultCache() +// unresolved, err := cache.InjectDevices(spec, devices) +// if err != nil { +// return fmt.Errorf("CDI device injection failed: %w", err) +// } +// +// log.Debug("CDI-updated OCI Spec: %s", dumpSpec(spec)) +// return nil +// } +// +// # Cache Refresh +// +// By default the CDI Spec cache monitors the configured Spec directories +// and automatically refreshes itself when necessary. This behavior can be +// disabled using the WithAutoRefresh(false) option. +// +// Failure to set up monitoring for a Spec directory causes the directory to +// get ignored and an error to be recorded among the Spec directory errors. +// These errors can be queried using the GetSpecDirErrors() function. If the +// error condition is transient, for instance a missing directory which later +// gets created, the corresponding error will be removed once the condition +// is over. +// +// With auto-refresh enabled injecting any CDI devices can be done without +// an explicit call to Refresh(), using a code snippet similar to the +// following: +// +// In a runtime implementation one typically wants to make sure the +// CDI Spec cache is up to date before performing device injection. +// A code snippet similar to the following accmplishes that: +// +// import ( +// "fmt" +// "strings" +// +// log "github.com/sirupsen/logrus" +// +// "tags.cncf.io/container-device-interface/pkg/cdi" +// "github.com/opencontainers/runtime-spec/specs-go" +// ) +// +// func injectCDIDevices(spec *specs.Spec, devices []string) error { +// cache := cdi.GetDefaultCache() +// +// if err := cache.Refresh(); err != nil { +// // Note: +// // It is up to the implementation to decide whether +// // to abort injection on errors. A failed Refresh() +// // does not necessarily render the cache unusable. +// // For instance, a parse error in a Spec file for +// // vendor A does not have any effect on devices of +// // vendor B... +// log.Warnf("pre-injection Refresh() failed: %v", err) +// } +// +// log.Debug("pristine OCI Spec: %s", dumpSpec(spec)) +// +// unresolved, err := cache.InjectDevices(spec, devices) +// if err != nil { +// return fmt.Errorf("CDI device injection failed: %w", err) +// } +// +// log.Debug("CDI-updated OCI Spec: %s", dumpSpec(spec)) +// return nil +// } +// +// # Generated Spec Files, Multiple Directories, Device Precedence +// +// It is often necessary to generate Spec files dynamically. On some +// systems the available or usable set of CDI devices might change +// dynamically which then needs to be reflected in CDI Specs. For +// some device classes it makes sense to enumerate the available +// devices at every boot and generate Spec file entries for each +// device found. Some CDI devices might need special client- or +// request-specific configuration which can only be fulfilled by +// dynamically generated client-specific entries in transient Spec +// files. +// +// CDI can collect Spec files from multiple directories. Spec files are +// automatically assigned priorities according to which directory they +// were loaded from. The later a directory occurs in the list of CDI +// directories to scan, the higher priority Spec files loaded from that +// directory are assigned to. When two or more Spec files define the +// same device, conflict is resolved by choosing the definition from the +// Spec file with the highest priority. +// +// The default CDI directory configuration is chosen to encourage +// separating dynamically generated CDI Spec files from static ones. +// The default directories are '/etc/cdi' and '/var/run/cdi'. By putting +// dynamically generated Spec files under '/var/run/cdi', those take +// precedence over static ones in '/etc/cdi'. With this scheme, static +// Spec files, typically installed by distro-specific packages, go into +// '/etc/cdi' while all the dynamically generated Spec files, transient +// or other, go into '/var/run/cdi'. +// +// # Spec File Generation +// +// CDI offers two functions for writing and removing dynamically generated +// Specs from CDI Spec directories. These functions, WriteSpec() and +// RemoveSpec() implicitly follow the principle of separating dynamic Specs +// from the rest and therefore always write to and remove Specs from the +// last configured directory. +// +// Corresponding functions are also provided for generating names for Spec +// files. These functions follow a simple naming convention to ensure that +// multiple entities generating Spec files simultaneously on the same host +// do not end up using conflicting Spec file names. GenerateSpecName(), +// GenerateNameForSpec(), GenerateTransientSpecName(), and +// GenerateTransientNameForSpec() all generate names which can be passed +// as such to WriteSpec() and subsequently to RemoveSpec(). +// +// Generating a Spec file for a vendor/device class can be done with a +// code snippet similar to the following: +// +// import ( +// +// "fmt" +// ... +// "tags.cncf.io/container-device-interface/specs-go" +// "tags.cncf.io/container-device-interface/pkg/cdi" +// +// ) +// +// func generateDeviceSpecs() error { +// cache := specs.GetDefaultCache() +// spec := &specs.Spec{ +// Version: specs.CurrentVersion, +// Kind: vendor+"/"+class, +// } +// +// for _, dev := range enumerateDevices() { +// spec.Devices = append(spec.Devices, specs.Device{ +// Name: dev.Name, +// ContainerEdits: getContainerEditsForDevice(dev), +// }) +// } +// +// specName, err := cdi.GenerateNameForSpec(spec) +// if err != nil { +// return fmt.Errorf("failed to generate Spec name: %w", err) +// } +// +// return cache.WriteSpec(spec, specName) +// } +// +// Similarly, generating and later cleaning up transient Spec files can be +// done with code fragments similar to the following. These transient Spec +// files are temporary Spec files with container-specific parametrization. +// They are typically created before the associated container is created +// and removed once that container is removed. +// +// import ( +// +// "fmt" +// ... +// "tags.cncf.io/container-device-interface/specs-go" +// "tags.cncf.io/container-device-interface/pkg/cdi" +// +// ) +// +// func generateTransientSpec(ctr Container) error { +// cache := specs.GetDefaultCache() +// devices := getContainerDevs(ctr, vendor, class) +// spec := &specs.Spec{ +// Version: specs.CurrentVersion, +// Kind: vendor+"/"+class, +// } +// +// for _, dev := range devices { +// spec.Devices = append(spec.Devices, specs.Device{ +// // the generated name needs to be unique within the +// // vendor/class domain on the host/node. +// Name: generateUniqueDevName(dev, ctr), +// ContainerEdits: getEditsForContainer(dev), +// }) +// } +// +// // transientID is expected to guarantee that the Spec file name +// // generated using is unique within +// // the host/node. If more than one device is allocated with the +// // same vendor/class domain, either all generated Spec entries +// // should go to a single Spec file (like in this sample snippet), +// // or transientID should be unique for each generated Spec file. +// transientID := getSomeSufficientlyUniqueIDForContainer(ctr) +// specName, err := cdi.GenerateNameForTransientSpec(vendor, class, transientID) +// if err != nil { +// return fmt.Errorf("failed to generate Spec name: %w", err) +// } +// +// return cache.WriteSpec(spec, specName) +// } +// +// func removeTransientSpec(ctr Container) error { +// cache := specs.GetDefaultCache() +// transientID := getSomeSufficientlyUniqueIDForContainer(ctr) +// specName := cdi.GenerateNameForTransientSpec(vendor, class, transientID) +// +// return cache.RemoveSpec(specName) +// } +// +// # CDI Spec Validation +// +// This package performs both syntactic and semantic validation of CDI +// Spec file data when a Spec file is loaded via the cache or using +// the ReadSpec API function. As part of the semantic verification, the +// Spec file is verified against the CDI Spec JSON validation schema. +// +// If a valid externally provided JSON validation schema is found in +// the filesystem at /etc/cdi/schema/schema.json it is loaded and used +// as the default validation schema. If such a file is not found or +// fails to load, an embedded no-op schema is used. +// +// The used validation schema can also be changed programmatically using +// the SetSchema API convenience function. This function also accepts +// the special "builtin" (BuiltinSchemaName) and "none" (NoneSchemaName) +// schema names which switch the used schema to the in-repo validation +// schema embedded into the binary or the now default no-op schema +// correspondingly. Other names are interpreted as the path to the actual +// validation schema to load and use. +package cdi diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/oci.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/oci.go new file mode 100644 index 00000000..4d62c41f --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/oci.go @@ -0,0 +1,65 @@ +/* +Copyright © 2021 The CDI Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cdi + +import ( + spec "github.com/opencontainers/runtime-spec/specs-go" +) + +// toOCI returns the opencontainers runtime Spec Hook for this Hook. +func (h *Hook) toOCI() spec.Hook { + return spec.Hook{ + Path: h.Path, + Args: h.Args, + Env: h.Env, + Timeout: h.Timeout, + } +} + +// toOCI returns the opencontainers runtime Spec Mount for this Mount. +func (m *Mount) toOCI() spec.Mount { + return spec.Mount{ + Source: m.HostPath, + Destination: m.ContainerPath, + Options: m.Options, + Type: m.Type, + } +} + +// toOCI returns the opencontainers runtime Spec LinuxDevice for this DeviceNode. +func (d *DeviceNode) toOCI() spec.LinuxDevice { + return spec.LinuxDevice{ + Path: d.Path, + Type: d.Type, + Major: d.Major, + Minor: d.Minor, + FileMode: d.FileMode, + UID: d.UID, + GID: d.GID, + } +} + +// toOCI returns the opencontainers runtime Spec LinuxIntelRdt for this IntelRdt config. +func (i *IntelRdt) toOCI() *spec.LinuxIntelRdt { + return &spec.LinuxIntelRdt{ + ClosID: i.ClosID, + L3CacheSchema: i.L3CacheSchema, + MemBwSchema: i.MemBwSchema, + EnableCMT: i.EnableCMT, + EnableMBM: i.EnableMBM, + } +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec-dirs.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec-dirs.go new file mode 100644 index 00000000..b192f962 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec-dirs.go @@ -0,0 +1,112 @@ +/* + Copyright © 2021 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import ( + "errors" + "io/fs" + "os" + "path/filepath" +) + +const ( + // DefaultStaticDir is the default directory for static CDI Specs. + DefaultStaticDir = "/etc/cdi" + // DefaultDynamicDir is the default directory for generated CDI Specs + DefaultDynamicDir = "/var/run/cdi" +) + +var ( + // DefaultSpecDirs is the default Spec directory configuration. + // While altering this variable changes the package defaults, + // the preferred way of overriding the default directories is + // to use a WithSpecDirs options. Otherwise the change is only + // effective if it takes place before creating the cache instance. + DefaultSpecDirs = []string{DefaultStaticDir, DefaultDynamicDir} + // ErrStopScan can be returned from a ScanSpecFunc to stop the scan. + ErrStopScan = errors.New("stop Spec scan") +) + +// WithSpecDirs returns an option to override the CDI Spec directories. +func WithSpecDirs(dirs ...string) Option { + return func(c *Cache) { + specDirs := make([]string, len(dirs)) + for i, dir := range dirs { + specDirs[i] = filepath.Clean(dir) + } + c.specDirs = specDirs + } +} + +// scanSpecFunc is a function for processing CDI Spec files. +type scanSpecFunc func(string, int, *Spec, error) error + +// ScanSpecDirs scans the given directories looking for CDI Spec files, +// which are all files with a '.json' or '.yaml' suffix. For every Spec +// file discovered, ScanSpecDirs loads a Spec from the file then calls +// the scan function passing it the path to the file, the priority (the +// index of the directory in the slice of directories given), the Spec +// itself, and any error encountered while loading the Spec. +// +// Scanning stops once all files have been processed or when the scan +// function returns an error. The result of ScanSpecDirs is the error +// returned by the scan function, if any. The special error ErrStopScan +// can be used to terminate the scan gracefully without ScanSpecDirs +// returning an error. ScanSpecDirs silently skips any subdirectories. +func scanSpecDirs(dirs []string, scanFn scanSpecFunc) error { + var ( + spec *Spec + err error + ) + + for priority, dir := range dirs { + err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + // for initial stat failure Walk calls us with nil info + if info == nil { + if errors.Is(err, fs.ErrNotExist) { + return nil + } + return err + } + // first call from Walk is for dir itself, others we skip + if info.IsDir() { + if path == dir { + return nil + } + return filepath.SkipDir + } + + // ignore obviously non-Spec files + if ext := filepath.Ext(path); ext != ".json" && ext != ".yaml" { + return nil + } + + if err != nil { + return scanFn(path, priority, nil, err) + } + + spec, err = ReadSpec(path, priority) + return scanFn(path, priority, spec, err) + }) + + if err != nil && err != ErrStopScan { + return err + } + } + + return nil +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec.go new file mode 100644 index 00000000..8d295a83 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec.go @@ -0,0 +1,348 @@ +/* + Copyright © 2021 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "sync" + + oci "github.com/opencontainers/runtime-spec/specs-go" + orderedyaml "gopkg.in/yaml.v3" + "sigs.k8s.io/yaml" + + "tags.cncf.io/container-device-interface/internal/validation" + "tags.cncf.io/container-device-interface/pkg/parser" + cdi "tags.cncf.io/container-device-interface/specs-go" +) + +const ( + // defaultSpecExt is the file extension for the default encoding. + defaultSpecExt = ".yaml" +) + +type validator interface { + Validate(*cdi.Spec) error +} + +var ( + // Externally set CDI Spec validation function. + specValidator validator + validatorLock sync.RWMutex +) + +// Spec represents a single CDI Spec. It is usually loaded from a +// file and stored in a cache. The Spec has an associated priority. +// This priority is inherited from the associated priority of the +// CDI Spec directory that contains the CDI Spec file and is used +// to resolve conflicts if multiple CDI Spec files contain entries +// for the same fully qualified device. +type Spec struct { + *cdi.Spec + vendor string + class string + path string + priority int + devices map[string]*Device +} + +// ReadSpec reads the given CDI Spec file. The resulting Spec is +// assigned the given priority. If reading or parsing the Spec +// data fails ReadSpec returns a nil Spec and an error. +func ReadSpec(path string, priority int) (*Spec, error) { + data, err := os.ReadFile(path) + switch { + case os.IsNotExist(err): + return nil, err + case err != nil: + return nil, fmt.Errorf("failed to read CDI Spec %q: %w", path, err) + } + + raw, err := ParseSpec(data) + if err != nil { + return nil, fmt.Errorf("failed to parse CDI Spec %q: %w", path, err) + } + if raw == nil { + return nil, fmt.Errorf("failed to parse CDI Spec %q, no Spec data", path) + } + + spec, err := newSpec(raw, path, priority) + if err != nil { + return nil, err + } + + return spec, nil +} + +// newSpec creates a new Spec from the given CDI Spec data. The +// Spec is marked as loaded from the given path with the given +// priority. If Spec data validation fails newSpec returns a nil +// Spec and an error. +func newSpec(raw *cdi.Spec, path string, priority int) (*Spec, error) { + err := validateSpec(raw) + if err != nil { + return nil, err + } + + spec := &Spec{ + Spec: raw, + path: filepath.Clean(path), + priority: priority, + } + + if ext := filepath.Ext(spec.path); ext != ".yaml" && ext != ".json" { + spec.path += defaultSpecExt + } + + spec.vendor, spec.class = parser.ParseQualifier(spec.Kind) + + if spec.devices, err = spec.validate(); err != nil { + return nil, fmt.Errorf("invalid CDI Spec: %w", err) + } + + return spec, nil +} + +// Write the CDI Spec to the file associated with it during instantiation +// by newSpec() or ReadSpec(). +func (s *Spec) write(overwrite bool) error { + var ( + data []byte + dir string + tmp *os.File + err error + ) + + err = validateSpec(s.Spec) + if err != nil { + return err + } + + if filepath.Ext(s.path) == ".yaml" { + data, err = orderedyaml.Marshal(s.Spec) + data = append([]byte("---\n"), data...) + } else { + data, err = json.Marshal(s.Spec) + } + if err != nil { + return fmt.Errorf("failed to marshal Spec file: %w", err) + } + + dir = filepath.Dir(s.path) + err = os.MkdirAll(dir, 0o755) + if err != nil { + return fmt.Errorf("failed to create Spec dir: %w", err) + } + + tmp, err = os.CreateTemp(dir, "spec.*.tmp") + if err != nil { + return fmt.Errorf("failed to create Spec file: %w", err) + } + _, err = tmp.Write(data) + tmp.Close() + if err != nil { + return fmt.Errorf("failed to write Spec file: %w", err) + } + + err = renameIn(dir, filepath.Base(tmp.Name()), filepath.Base(s.path), overwrite) + + if err != nil { + os.Remove(tmp.Name()) + err = fmt.Errorf("failed to write Spec file: %w", err) + } + + return err +} + +// GetVendor returns the vendor of this Spec. +func (s *Spec) GetVendor() string { + return s.vendor +} + +// GetClass returns the device class of this Spec. +func (s *Spec) GetClass() string { + return s.class +} + +// GetDevice returns the device for the given unqualified name. +func (s *Spec) GetDevice(name string) *Device { + return s.devices[name] +} + +// GetPath returns the filesystem path of this Spec. +func (s *Spec) GetPath() string { + return s.path +} + +// GetPriority returns the priority of this Spec. +func (s *Spec) GetPriority() int { + return s.priority +} + +// ApplyEdits applies the Spec's global-scope container edits to an OCI Spec. +func (s *Spec) ApplyEdits(ociSpec *oci.Spec) error { + return s.edits().Apply(ociSpec) +} + +// edits returns the applicable global container edits for this spec. +func (s *Spec) edits() *ContainerEdits { + return &ContainerEdits{&s.ContainerEdits} +} + +// MinimumRequiredVersion determines the minimum spec version for the input spec. +// Deprecated: use cdi.MinimumRequiredVersion instead +func MinimumRequiredVersion(spec *cdi.Spec) (string, error) { + return cdi.MinimumRequiredVersion(spec) +} + +// Validate the Spec. +func (s *Spec) validate() (map[string]*Device, error) { + if err := cdi.ValidateVersion(s.Spec); err != nil { + return nil, err + } + if err := parser.ValidateVendorName(s.vendor); err != nil { + return nil, err + } + if err := parser.ValidateClassName(s.class); err != nil { + return nil, err + } + if err := validation.ValidateSpecAnnotations(s.Kind, s.Annotations); err != nil { + return nil, err + } + if err := s.edits().Validate(); err != nil { + return nil, err + } + + devices := make(map[string]*Device) + for _, d := range s.Devices { + dev, err := newDevice(s, d) + if err != nil { + return nil, fmt.Errorf("failed add device %q: %w", d.Name, err) + } + if _, conflict := devices[d.Name]; conflict { + return nil, fmt.Errorf("invalid spec, multiple device %q", d.Name) + } + devices[d.Name] = dev + } + if len(devices) == 0 { + return nil, fmt.Errorf("invalid spec, no devices") + } + + return devices, nil +} + +// ParseSpec parses CDI Spec data into a raw CDI Spec. +func ParseSpec(data []byte) (*cdi.Spec, error) { + var raw *cdi.Spec + err := yaml.UnmarshalStrict(data, &raw) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal CDI Spec: %w", err) + } + return raw, nil +} + +// SetSpecValidator sets a CDI Spec validator function. This function +// is used for extra CDI Spec content validation whenever a Spec file +// loaded (using ReadSpec() or written (using WriteSpec()). +func SetSpecValidator(v validator) { + validatorLock.Lock() + defer validatorLock.Unlock() + specValidator = v +} + +// validateSpec validates the Spec using the external validator. +func validateSpec(raw *cdi.Spec) error { + validatorLock.RLock() + defer validatorLock.RUnlock() + + if specValidator == nil { + return nil + } + err := specValidator.Validate(raw) + if err != nil { + return fmt.Errorf("Spec validation failed: %w", err) + } + return nil +} + +// GenerateSpecName generates a vendor+class scoped Spec file name. The +// name can be passed to WriteSpec() to write a Spec file to the file +// system. +// +// vendor and class should match the vendor and class of the CDI Spec. +// The file name is generated without a ".json" or ".yaml" extension. +// The caller can append the desired extension to choose a particular +// encoding. Otherwise WriteSpec() will use its default encoding. +// +// This function always returns the same name for the same vendor/class +// combination. Therefore it cannot be used as such to generate multiple +// Spec file names for a single vendor and class. +func GenerateSpecName(vendor, class string) string { + return vendor + "-" + class +} + +// GenerateTransientSpecName generates a vendor+class scoped transient +// Spec file name. The name can be passed to WriteSpec() to write a Spec +// file to the file system. +// +// Transient Specs are those whose lifecycle is tied to that of some +// external entity, for instance a container. vendor and class should +// match the vendor and class of the CDI Spec. transientID should be +// unique among all CDI users on the same host that might generate +// transient Spec files using the same vendor/class combination. If +// the external entity to which the lifecycle of the transient Spec +// is tied to has a unique ID of its own, then this is usually a +// good choice for transientID. +// +// The file name is generated without a ".json" or ".yaml" extension. +// The caller can append the desired extension to choose a particular +// encoding. Otherwise WriteSpec() will use its default encoding. +func GenerateTransientSpecName(vendor, class, transientID string) string { + transientID = strings.ReplaceAll(transientID, "/", "_") + return GenerateSpecName(vendor, class) + "_" + transientID +} + +// GenerateNameForSpec generates a name for the given Spec using +// GenerateSpecName with the vendor and class taken from the Spec. +// On success it returns the generated name and a nil error. If +// the Spec does not contain a valid vendor or class, it returns +// an empty name and a non-nil error. +func GenerateNameForSpec(raw *cdi.Spec) (string, error) { + vendor, class := parser.ParseQualifier(raw.Kind) + if vendor == "" { + return "", fmt.Errorf("invalid vendor/class %q in Spec", raw.Kind) + } + + return GenerateSpecName(vendor, class), nil +} + +// GenerateNameForTransientSpec generates a name for the given transient +// Spec using GenerateTransientSpecName with the vendor and class taken +// from the Spec. On success it returns the generated name and a nil error. +// If the Spec does not contain a valid vendor or class, it returns an +// an empty name and a non-nil error. +func GenerateNameForTransientSpec(raw *cdi.Spec, transientID string) (string, error) { + vendor, class := parser.ParseQualifier(raw.Kind) + if vendor == "" { + return "", fmt.Errorf("invalid vendor/class %q in Spec", raw.Kind) + } + + return GenerateTransientSpecName(vendor, class, transientID), nil +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec_linux.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec_linux.go new file mode 100644 index 00000000..9ad27392 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec_linux.go @@ -0,0 +1,48 @@ +/* + Copyright © 2022 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import ( + "fmt" + "os" + + "golang.org/x/sys/unix" +) + +// Rename src to dst, both relative to the directory dir. If dst already exists +// refuse renaming with an error unless overwrite is explicitly asked for. +func renameIn(dir, src, dst string, overwrite bool) error { + var flags uint + + dirf, err := os.Open(dir) + if err != nil { + return fmt.Errorf("rename failed: %w", err) + } + defer dirf.Close() + + if !overwrite { + flags = unix.RENAME_NOREPLACE + } + + dirFd := int(dirf.Fd()) + err = unix.Renameat2(dirFd, src, dirFd, dst, flags) + if err != nil { + return fmt.Errorf("rename failed: %w", err) + } + + return nil +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec_other.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec_other.go new file mode 100644 index 00000000..285e04e2 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec_other.go @@ -0,0 +1,39 @@ +//go:build !linux +// +build !linux + +/* + Copyright © 2022 The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cdi + +import ( + "os" + "path/filepath" +) + +// Rename src to dst, both relative to the directory dir. If dst already exists +// refuse renaming with an error unless overwrite is explicitly asked for. +func renameIn(dir, src, dst string, overwrite bool) error { + src = filepath.Join(dir, src) + dst = filepath.Join(dir, dst) + + _, err := os.Stat(dst) + if err == nil && !overwrite { + return os.ErrExist + } + + return os.Rename(src, dst) +} diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/parser/parser.go b/vendor/tags.cncf.io/container-device-interface/pkg/parser/parser.go new file mode 100644 index 00000000..53259895 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/pkg/parser/parser.go @@ -0,0 +1,212 @@ +/* + Copyright © The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package parser + +import ( + "fmt" + "strings" +) + +// QualifiedName returns the qualified name for a device. +// The syntax for a qualified device names is +// +// "/=". +// +// A valid vendor and class name may contain the following runes: +// +// 'A'-'Z', 'a'-'z', '0'-'9', '.', '-', '_'. +// +// A valid device name may contain the following runes: +// +// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_', '.', ':' +func QualifiedName(vendor, class, name string) string { + return vendor + "/" + class + "=" + name +} + +// IsQualifiedName tests if a device name is qualified. +func IsQualifiedName(device string) bool { + _, _, _, err := ParseQualifiedName(device) + return err == nil +} + +// ParseQualifiedName splits a qualified name into device vendor, class, +// and name. If the device fails to parse as a qualified name, or if any +// of the split components fail to pass syntax validation, vendor and +// class are returned as empty, together with the verbatim input as the +// name and an error describing the reason for failure. +func ParseQualifiedName(device string) (string, string, string, error) { + vendor, class, name := ParseDevice(device) + + if vendor == "" { + return "", "", device, fmt.Errorf("unqualified device %q, missing vendor", device) + } + if class == "" { + return "", "", device, fmt.Errorf("unqualified device %q, missing class", device) + } + if name == "" { + return "", "", device, fmt.Errorf("unqualified device %q, missing device name", device) + } + + if err := ValidateVendorName(vendor); err != nil { + return "", "", device, fmt.Errorf("invalid device %q: %w", device, err) + } + if err := ValidateClassName(class); err != nil { + return "", "", device, fmt.Errorf("invalid device %q: %w", device, err) + } + if err := ValidateDeviceName(name); err != nil { + return "", "", device, fmt.Errorf("invalid device %q: %w", device, err) + } + + return vendor, class, name, nil +} + +// ParseDevice tries to split a device name into vendor, class, and name. +// If this fails, for instance in the case of unqualified device names, +// ParseDevice returns an empty vendor and class together with name set +// to the verbatim input. +func ParseDevice(device string) (string, string, string) { + if device == "" || device[0] == '/' { + return "", "", device + } + + parts := strings.SplitN(device, "=", 2) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", device + } + + name := parts[1] + vendor, class := ParseQualifier(parts[0]) + if vendor == "" { + return "", "", device + } + + return vendor, class, name +} + +// ParseQualifier splits a device qualifier into vendor and class. +// The syntax for a device qualifier is +// +// "/" +// +// If parsing fails, an empty vendor and the class set to the +// verbatim input is returned. +func ParseQualifier(kind string) (string, string) { + parts := strings.SplitN(kind, "/", 2) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", kind + } + return parts[0], parts[1] +} + +// ValidateVendorName checks the validity of a vendor name. +// A vendor name may contain the following ASCII characters: +// - upper- and lowercase letters ('A'-'Z', 'a'-'z') +// - digits ('0'-'9') +// - underscore, dash, and dot ('_', '-', and '.') +func ValidateVendorName(vendor string) error { + err := validateVendorOrClassName(vendor) + if err != nil { + err = fmt.Errorf("invalid vendor. %w", err) + } + return err +} + +// ValidateClassName checks the validity of class name. +// A class name may contain the following ASCII characters: +// - upper- and lowercase letters ('A'-'Z', 'a'-'z') +// - digits ('0'-'9') +// - underscore, dash, and dot ('_', '-', and '.') +func ValidateClassName(class string) error { + err := validateVendorOrClassName(class) + if err != nil { + err = fmt.Errorf("invalid class. %w", err) + } + return err +} + +// validateVendorOrClassName checks the validity of vendor or class name. +// A name may contain the following ASCII characters: +// - upper- and lowercase letters ('A'-'Z', 'a'-'z') +// - digits ('0'-'9') +// - underscore, dash, and dot ('_', '-', and '.') +func validateVendorOrClassName(name string) error { + if name == "" { + return fmt.Errorf("empty name") + } + if !IsLetter(rune(name[0])) { + return fmt.Errorf("%q, should start with letter", name) + } + for _, c := range string(name[1 : len(name)-1]) { + switch { + case IsAlphaNumeric(c): + case c == '_' || c == '-' || c == '.': + default: + return fmt.Errorf("invalid character '%c' in name %q", + c, name) + } + } + if !IsAlphaNumeric(rune(name[len(name)-1])) { + return fmt.Errorf("%q, should end with a letter or digit", name) + } + + return nil +} + +// ValidateDeviceName checks the validity of a device name. +// A device name may contain the following ASCII characters: +// - upper- and lowercase letters ('A'-'Z', 'a'-'z') +// - digits ('0'-'9') +// - underscore, dash, dot, colon ('_', '-', '.', ':') +func ValidateDeviceName(name string) error { + if name == "" { + return fmt.Errorf("invalid (empty) device name") + } + if !IsAlphaNumeric(rune(name[0])) { + return fmt.Errorf("invalid class %q, should start with a letter or digit", name) + } + if len(name) == 1 { + return nil + } + for _, c := range string(name[1 : len(name)-1]) { + switch { + case IsAlphaNumeric(c): + case c == '_' || c == '-' || c == '.' || c == ':': + default: + return fmt.Errorf("invalid character '%c' in device name %q", + c, name) + } + } + if !IsAlphaNumeric(rune(name[len(name)-1])) { + return fmt.Errorf("invalid name %q, should end with a letter or digit", name) + } + return nil +} + +// IsLetter reports whether the rune is a letter. +func IsLetter(c rune) bool { + return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') +} + +// IsDigit reports whether the rune is a digit. +func IsDigit(c rune) bool { + return '0' <= c && c <= '9' +} + +// IsAlphaNumeric reports whether the rune is a letter or digit. +func IsAlphaNumeric(c rune) bool { + return IsLetter(c) || IsDigit(c) +} diff --git a/vendor/tags.cncf.io/container-device-interface/specs-go/LICENSE b/vendor/tags.cncf.io/container-device-interface/specs-go/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/specs-go/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor 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, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/tags.cncf.io/container-device-interface/specs-go/config.go b/vendor/tags.cncf.io/container-device-interface/specs-go/config.go new file mode 100644 index 00000000..f28657b8 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/specs-go/config.go @@ -0,0 +1,72 @@ +package specs + +import "os" + +// Spec is the base configuration for CDI +type Spec struct { + Version string `json:"cdiVersion" yaml:"cdiVersion"` + Kind string `json:"kind" yaml:"kind"` + // Annotations add meta information per CDI spec. Note these are CDI-specific and do not affect container metadata. + // Added in v0.6.0. + Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` + Devices []Device `json:"devices" yaml:"devices"` + ContainerEdits ContainerEdits `json:"containerEdits,omitempty" yaml:"containerEdits,omitempty"` +} + +// Device is a "Device" a container runtime can add to a container +type Device struct { + Name string `json:"name" yaml:"name"` + // Annotations add meta information per device. Note these are CDI-specific and do not affect container metadata. + // Added in v0.6.0. + Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` + ContainerEdits ContainerEdits `json:"containerEdits" yaml:"containerEdits"` +} + +// ContainerEdits are edits a container runtime must make to the OCI spec to expose the device. +type ContainerEdits struct { + Env []string `json:"env,omitempty" yaml:"env,omitempty"` + DeviceNodes []*DeviceNode `json:"deviceNodes,omitempty" yaml:"deviceNodes,omitempty"` + Hooks []*Hook `json:"hooks,omitempty" yaml:"hooks,omitempty"` + Mounts []*Mount `json:"mounts,omitempty" yaml:"mounts,omitempty"` + IntelRdt *IntelRdt `json:"intelRdt,omitempty" yaml:"intelRdt,omitempty"` // Added in v0.7.0 + AdditionalGIDs []uint32 `json:"additionalGids,omitempty" yaml:"additionalGids,omitempty"` // Added in v0.7.0 +} + +// DeviceNode represents a device node that needs to be added to the OCI spec. +type DeviceNode struct { + Path string `json:"path" yaml:"path"` + HostPath string `json:"hostPath,omitempty" yaml:"hostPath,omitempty"` // Added in v0.5.0 + Type string `json:"type,omitempty" yaml:"type,omitempty"` + Major int64 `json:"major,omitempty" yaml:"major,omitempty"` + Minor int64 `json:"minor,omitempty" yaml:"minor,omitempty"` + FileMode *os.FileMode `json:"fileMode,omitempty" yaml:"fileMode,omitempty"` + Permissions string `json:"permissions,omitempty" yaml:"permissions,omitempty"` + UID *uint32 `json:"uid,omitempty" yaml:"uid,omitempty"` + GID *uint32 `json:"gid,omitempty" yaml:"gid,omitempty"` +} + +// Mount represents a mount that needs to be added to the OCI spec. +type Mount struct { + HostPath string `json:"hostPath" yaml:"hostPath"` + ContainerPath string `json:"containerPath" yaml:"containerPath"` + Options []string `json:"options,omitempty" yaml:"options,omitempty"` + Type string `json:"type,omitempty" yaml:"type,omitempty"` // Added in v0.4.0 +} + +// Hook represents a hook that needs to be added to the OCI spec. +type Hook struct { + HookName string `json:"hookName" yaml:"hookName"` + Path string `json:"path" yaml:"path"` + Args []string `json:"args,omitempty" yaml:"args,omitempty"` + Env []string `json:"env,omitempty" yaml:"env,omitempty"` + Timeout *int `json:"timeout,omitempty" yaml:"timeout,omitempty"` +} + +// IntelRdt describes the Linux IntelRdt parameters to set in the OCI spec. +type IntelRdt struct { + ClosID string `json:"closID,omitempty" yaml:"closID,omitempty"` + L3CacheSchema string `json:"l3CacheSchema,omitempty" yaml:"l3CacheSchema,omitempty"` + MemBwSchema string `json:"memBwSchema,omitempty" yaml:"memBwSchema,omitempty"` + EnableCMT bool `json:"enableCMT,omitempty" yaml:"enableCMT,omitempty"` + EnableMBM bool `json:"enableMBM,omitempty" yaml:"enableMBM,omitempty"` +} diff --git a/vendor/tags.cncf.io/container-device-interface/specs-go/version.go b/vendor/tags.cncf.io/container-device-interface/specs-go/version.go new file mode 100644 index 00000000..002e0350 --- /dev/null +++ b/vendor/tags.cncf.io/container-device-interface/specs-go/version.go @@ -0,0 +1,244 @@ +/* + Copyright © The CDI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package specs + +import ( + "fmt" + "strings" + + "golang.org/x/mod/semver" +) + +const ( + // CurrentVersion is the current version of the Spec. + CurrentVersion = "1.0.0" + + // vCurrent is the current version as a semver-comparable type + vCurrent version = "v" + CurrentVersion + + // These represent the released versions of the CDI specification + v010 version = "v0.1.0" + v020 version = "v0.2.0" + v030 version = "v0.3.0" + v040 version = "v0.4.0" + v050 version = "v0.5.0" + v060 version = "v0.6.0" + v070 version = "v0.7.0" + v080 version = "v0.8.0" + v100 version = "v1.0.0" + + // vEarliest is the earliest supported version of the CDI specification + vEarliest version = v030 +) + +// validSpecVersions stores a map of spec versions to functions to check the required versions. +// Adding new fields / spec versions requires that a `requiredFunc` be implemented and +// this map be updated. +var validSpecVersions = requiredVersionMap{ + v010: nil, + v020: nil, + v030: nil, + v040: requiresV040, + v050: requiresV050, + v060: requiresV060, + v070: requiresV070, + v080: requiresV080, + v100: requiresV100, +} + +// ValidateVersion checks whether the specified spec version is valid. +// In addition to checking whether the spec version is in the set of known versions, +// the spec is inspected to determine whether the features used are available in specified +// version. +func ValidateVersion(spec *Spec) error { + if !validSpecVersions.isValidVersion(spec.Version) { + return fmt.Errorf("invalid version %q", spec.Version) + } + minVersion, err := MinimumRequiredVersion(spec) + if err != nil { + return fmt.Errorf("could not determine minimum required version: %w", err) + } + if newVersion(minVersion).isGreaterThan(newVersion(spec.Version)) { + return fmt.Errorf("the spec version must be at least v%v", minVersion) + } + return nil +} + +// MinimumRequiredVersion determines the minimum spec version for the input spec. +func MinimumRequiredVersion(spec *Spec) (string, error) { + minVersion := validSpecVersions.requiredVersion(spec) + return minVersion.String(), nil +} + +// version represents a semantic version string +type version string + +// newVersion creates a version that can be used for semantic version comparisons. +func newVersion(v string) version { + return version("v" + strings.TrimPrefix(v, "v")) +} + +// String returns the string representation of the version. +// This trims a leading v if present. +func (v version) String() string { + return strings.TrimPrefix(string(v), "v") +} + +// isGreaterThan checks with a version is greater than the specified version. +func (v version) isGreaterThan(o version) bool { + return semver.Compare(string(v), string(o)) > 0 +} + +// isLatest checks whether the version is the latest supported version +func (v version) isLatest() bool { + return v == vCurrent +} + +type requiredFunc func(*Spec) bool + +type requiredVersionMap map[version]requiredFunc + +// isValidVersion checks whether the specified version is valid. +// A version is valid if it is contained in the required version map. +func (r requiredVersionMap) isValidVersion(specVersion string) bool { + _, ok := validSpecVersions[newVersion(specVersion)] + + return ok +} + +// requiredVersion returns the minimum version required for the given spec +func (r requiredVersionMap) requiredVersion(spec *Spec) version { + minVersion := vEarliest + + for v, isRequired := range validSpecVersions { + if isRequired == nil { + continue + } + if isRequired(spec) && v.isGreaterThan(minVersion) { + minVersion = v + } + // If we have already detected the latest version then no later version could be detected + if minVersion.isLatest() { + break + } + } + + return minVersion +} + +// requiresV100 returns true if the spec uses v1.0.0 features. +// Since the v1.0.0 spec bump was due to moving the minimum version checks to +// the spec package, there are no explicit spec changes. +func requiresV100(_ *Spec) bool { + return false +} + +// requiresV080 returns true if the spec uses v0.8.0 features. +// Since the v0.8.0 spec bump was due to the removed .ToOCI functions on the +// spec types, there are no explicit spec changes. +func requiresV080(_ *Spec) bool { + return false +} + +// requiresV070 returns true if the spec uses v0.7.0 features +func requiresV070(spec *Spec) bool { + if spec.ContainerEdits.IntelRdt != nil { + return true + } + // The v0.7.0 spec allows additional GIDs to be specified at a spec level. + if len(spec.ContainerEdits.AdditionalGIDs) > 0 { + return true + } + + for _, d := range spec.Devices { + if d.ContainerEdits.IntelRdt != nil { + return true + } + // The v0.7.0 spec allows additional GIDs to be specified at a device level. + if len(d.ContainerEdits.AdditionalGIDs) > 0 { + return true + } + } + + return false +} + +// requiresV060 returns true if the spec uses v0.6.0 features +func requiresV060(spec *Spec) bool { + // The v0.6.0 spec allows annotations to be specified at a spec level + for range spec.Annotations { + return true + } + + // The v0.6.0 spec allows annotations to be specified at a device level + for _, d := range spec.Devices { + for range d.Annotations { + return true + } + } + + // The v0.6.0 spec allows dots "." in Kind name label (class) + if !strings.Contains(spec.Kind, "/") { + return false + } + class := strings.SplitN(spec.Kind, "/", 2)[1] + return strings.Contains(class, ".") +} + +// requiresV050 returns true if the spec uses v0.5.0 features +func requiresV050(spec *Spec) bool { + var edits []*ContainerEdits + + for _, d := range spec.Devices { + // The v0.5.0 spec allowed device name to start with a digit + if len(d.Name) > 0 && '0' <= d.Name[0] && d.Name[0] <= '9' { + return true + } + edits = append(edits, &d.ContainerEdits) + } + + edits = append(edits, &spec.ContainerEdits) + for _, e := range edits { + for _, dn := range e.DeviceNodes { + // The HostPath field was added in v0.5.0 + if dn.HostPath != "" { + return true + } + } + } + return false +} + +// requiresV040 returns true if the spec uses v0.4.0 features +func requiresV040(spec *Spec) bool { + var edits []*ContainerEdits + + for _, d := range spec.Devices { + edits = append(edits, &d.ContainerEdits) + } + + edits = append(edits, &spec.ContainerEdits) + for _, e := range edits { + for _, m := range e.Mounts { + // The Type field was added in v0.4.0 + if m.Type != "" { + return true + } + } + } + return false +}