1// Program mknames parses the cap_names.h file and creates an 2// equivalent names.go file including comments on each cap.Value from 3// the documentation directory. 4package main 5 6import ( 7 "bytes" 8 "flag" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "log" 13 "strings" 14) 15 16var ( 17 header = flag.String("header", "", "name of header file") 18 text = flag.String("textdir", "", "directory name for value txt files") 19) 20 21func main() { 22 flag.Parse() 23 24 if *header == "" { 25 log.Fatal("usage: mknames --header=.../cap_names.h") 26 } 27 d, err := ioutil.ReadFile(*header) 28 if err != nil { 29 log.Fatal("reading:", err) 30 } 31 32 b := bytes.NewBuffer(d) 33 34 var list []string 35 for { 36 line, err := b.ReadString('\n') 37 if err == io.EOF { 38 break 39 } 40 if !strings.Contains(line, `"`) { 41 continue 42 } 43 i := strings.Index(line, `"`) 44 line = line[i+1:] 45 i = strings.Index(line, `"`) 46 line = line[:i] 47 list = append(list, line) 48 } 49 50 // generate package file names.go 51 fmt.Print(`package cap 52 53/* ** DO NOT EDIT THIS FILE. IT WAS AUTO-GENERATED BY LIBCAP'S GO BUILDER (mknames.go) ** */ 54 55// NamedCount holds the number of capability values with official 56// names known at the time this libcap/cap version, was released. The 57// "../libcap/cap" package is fully able to manipulate higher numbered 58// capability values by numerical value. However, if you find 59// cap.NamedCount < cap.MaxBits(), it is probably time to upgrade this 60// package on your system. 61// 62// FWIW the userspace tool '/sbin/capsh' also contains a runtime check 63// for the condition that libcap is behind the running kernel in this 64// way. 65const NamedCount = `, len(list), ` 66 67// CHOWN etc., are the named capability values of the Linux 68// kernel. The canonical source for each name is the 69// "uapi/linux/capabilities.h" file. Some values may not be available 70// (yet) where the kernel is older. The actual number of capabities 71// supported by the running kernel can be obtained using the 72// cap.MaxBits() function. 73const ( 74`) 75 bits := make(map[string]string) 76 for i, name := range list { 77 doc := fmt.Sprintf("%s/%d.txt", *text, i) 78 content, err := ioutil.ReadFile(doc) 79 if err != nil { 80 log.Fatalf("filed to read %q: %v", doc, err) 81 } 82 detail := strings.Split(strings.Replace(string(content), "CAP_", "cap.", -1), "\n") 83 if i != 0 { 84 fmt.Println() 85 } 86 v := strings.ToUpper(strings.TrimPrefix(name, "cap_")) 87 for j, line := range detail { 88 preamble := "" 89 offset := 0 90 if j == 0 { 91 if !strings.HasPrefix(line, "Allows ") { 92 log.Fatalf("line should begin \"Allows \": got %s:%d:%q", doc, j, line) 93 } 94 preamble = fmt.Sprint(v, " a") 95 offset = 1 96 } 97 if len(line) != 0 || j != len(detail)-1 { 98 fmt.Printf(" // %s%s\n", preamble, line[offset:]) 99 } 100 } 101 bits[name] = v 102 if i == 0 { 103 fmt.Println(v, " Value = iota") 104 } else { 105 fmt.Println(v) 106 } 107 } 108 fmt.Print(`) 109 110var names = map[Value]string{ 111`) 112 for _, name := range list { 113 fmt.Printf("%s: %q,\n", bits[name], name) 114 } 115 fmt.Print(`} 116 117var bits = map[string]Value { 118`) 119 for _, name := range list { 120 fmt.Printf("%q: %s,\n", name, bits[name]) 121 } 122 fmt.Println(`}`) 123} 124