gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/website/cmd/syscalldocs/main.go (about) 1 // Copyright 2019 The gVisor Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Binary syscalldocs generates system call markdown. 16 package main 17 18 import ( 19 "bufio" 20 "encoding/json" 21 "flag" 22 "fmt" 23 "io" 24 "os" 25 "path/filepath" 26 "sort" 27 "strings" 28 "text/template" 29 ) 30 31 // CompatibilityInfo is the collection of all information. 32 type CompatibilityInfo map[string]map[string]ArchInfo 33 34 // ArchInfo is compatbility doc for an architecture. 35 type ArchInfo struct { 36 // Syscalls maps syscall number for the architecture to the doc. 37 Syscalls map[uintptr]SyscallDoc `json:"syscalls"` 38 } 39 40 // SyscallDoc represents a single item of syscall documentation. 41 type SyscallDoc struct { 42 Name string `json:"name"` 43 Support string `json:"support"` 44 Note string `json:"note,omitempty"` 45 URLs []string `json:"urls,omitempty"` 46 } 47 48 var mdTemplate = template.Must(template.New("out").Parse(`--- 49 title: {{.Title}} 50 description: Syscall Compatibility Reference Documentation for {{.OS}}/{{.Arch}} 51 layout: docs 52 category: Compatibility 53 weight: 50 54 permalink: /docs/user_guide/compatibility/{{.OS}}/{{.Arch}}/ 55 include_in_menu: True 56 --- 57 58 This table is a reference of {{.OS}} syscalls for the {{.Arch}} architecture and 59 their compatibility status in gVisor. gVisor does not support all syscalls and 60 some syscalls may have a partial implementation. 61 62 This page is automatically generated from the source code. 63 64 Of {{.Total}} syscalls, {{.Supported}} syscalls have a full or partial 65 implementation. There are currently {{.Unsupported}} unsupported 66 syscalls. {{if .Undocumented}}{{.Undocumented}} syscalls are not yet documented.{{end}} 67 68 <table> 69 <thead> 70 <tr> 71 <th>#</th> 72 <th>Name</th> 73 <th>Support</th> 74 <th>Notes</th> 75 </tr> 76 </thead> 77 <tbody> 78 {{range $i, $syscall := .Syscalls}} 79 <tr id="{{.Name}}"> 80 <td><a href="#{{.Name}}">{{.Number}}</a></td> 81 <td><a href="{{.DocURL}}" target="_blank" rel="noopener">{{.Name}}</a></td> 82 <td>{{.Support}}</td> 83 <td>{{.Note}} {{range $i, $url := .URLs}}<br/>See: <a href="{{.}}">{{.}}</a>{{end}}</td> 84 </tr> 85 {{end}} 86 </tbody> 87 </table> 88 `)) 89 90 // Fatalf writes a message to stderr and exits with error code 1 91 func Fatalf(format string, a ...any) { 92 fmt.Fprintf(os.Stderr, format, a...) 93 os.Exit(1) 94 } 95 96 // syscallDocURL returns a doc url for a given syscall, doing its best to return a url that exists. 97 func syscallDocURL(name string) string { 98 customDocs := map[string]string{ 99 "io_pgetevents": "https://man7.org/linux/man-pages/man2/syscalls.2.html", 100 "rseq": "https://man7.org/linux/man-pages/man2/syscalls.2.html", 101 "io_uring_setup": "https://manpages.debian.org/buster-backports/liburing-dev/io_uring_setup.2.en.html", 102 "io_uring_enter": "https://manpages.debian.org/buster-backports/liburing-dev/io_uring_enter.2.en.html", 103 "io_uring_register": "https://manpages.debian.org/buster-backports/liburing-dev/io_uring_register.2.en.html", 104 "open_tree": "https://man7.org/linux/man-pages/man2/syscalls.2.html", 105 "move_mount": "https://man7.org/linux/man-pages/man2/syscalls.2.html", 106 "fsopen": "https://man7.org/linux/man-pages/man2/syscalls.2.html", 107 "fsconfig": "https://man7.org/linux/man-pages/man2/syscalls.2.html", 108 "fsmount": "https://man7.org/linux/man-pages/man2/syscalls.2.html", 109 "fspick": "https://man7.org/linux/man-pages/man2/syscalls.2.html", 110 } 111 if url, ok := customDocs[name]; ok { 112 return url 113 } 114 return fmt.Sprintf("http://man7.org/linux/man-pages/man2/%s.2.html", name) 115 } 116 117 func main() { 118 inputFlag := flag.String("in", "-", "File to input ('-' for stdin)") 119 outputDir := flag.String("out", ".", "Directory to output files.") 120 121 flag.Parse() 122 123 var input io.Reader 124 if *inputFlag == "-" { 125 input = os.Stdin 126 } else { 127 i, err := os.Open(*inputFlag) 128 if err != nil { 129 Fatalf("Error opening %q: %v", *inputFlag, err) 130 } 131 input = i 132 } 133 input = bufio.NewReader(input) 134 135 var info CompatibilityInfo 136 d := json.NewDecoder(input) 137 if err := d.Decode(&info); err != nil { 138 Fatalf("Error reading json: %v", err) 139 } 140 141 weight := 0 142 for osName, osInfo := range info { 143 for archName, archInfo := range osInfo { 144 outDir := filepath.Join(*outputDir, osName) 145 outFile := filepath.Join(outDir, archName+".md") 146 147 if err := os.MkdirAll(outDir, 0755); err != nil { 148 Fatalf("Error creating directory %q: %v", *outputDir, err) 149 } 150 151 f, err := os.OpenFile(outFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) 152 if err != nil { 153 Fatalf("Error opening file %q: %v", outFile, err) 154 } 155 defer f.Close() 156 157 weight += 10 158 data := struct { 159 Title string 160 OS string 161 Arch string 162 Weight int 163 Total int 164 Supported int 165 Unsupported int 166 Undocumented int 167 Syscalls []struct { 168 Name string 169 Number uintptr 170 DocURL string 171 Support string 172 Note string 173 URLs []string 174 } 175 }{ 176 Title: strings.Title(osName) + "/" + archName, 177 OS: osName, 178 Arch: archName, 179 Weight: weight, 180 Total: 0, 181 Supported: 0, 182 Unsupported: 0, 183 Undocumented: 0, 184 Syscalls: []struct { 185 Name string 186 Number uintptr 187 DocURL string 188 Support string 189 Note string 190 URLs []string 191 }{}, 192 } 193 194 for num, s := range archInfo.Syscalls { 195 switch s.Support { 196 case "Full Support", "Partial Support": 197 data.Supported++ 198 case "Unimplemented": 199 data.Unsupported++ 200 default: 201 data.Undocumented++ 202 } 203 data.Total++ 204 205 for i := range s.URLs { 206 if !strings.HasPrefix(s.URLs[i], "http://") && !strings.HasPrefix(s.URLs[i], "https://") { 207 s.URLs[i] = "https://" + s.URLs[i] 208 } 209 } 210 211 data.Syscalls = append(data.Syscalls, struct { 212 Name string 213 Number uintptr 214 DocURL string 215 Support string 216 Note string 217 URLs []string 218 }{ 219 Name: s.Name, 220 Number: num, 221 DocURL: syscallDocURL(s.Name), 222 Support: s.Support, 223 Note: s.Note, 224 URLs: s.URLs, 225 }) 226 } 227 228 sort.Slice(data.Syscalls, func(i, j int) bool { 229 return data.Syscalls[i].Number < data.Syscalls[j].Number 230 }) 231 232 if err := mdTemplate.Execute(f, data); err != nil { 233 Fatalf("Error writing file %q: %v", outFile, err) 234 } 235 } 236 } 237 }