// Program mknames parses the cap_names.h file and creates an // equivalent names.go file including comments on each cap.Value from // the documentation directory. package main import ( "bytes" "flag" "fmt" "io" "io/ioutil" "log" "strings" ) var ( header = flag.String("header", "", "name of header file") text = flag.String("textdir", "", "directory name for value txt files") ) func main() { flag.Parse() if *header == "" { log.Fatal("usage: mknames --header=.../cap_names.h") } d, err := ioutil.ReadFile(*header) if err != nil { log.Fatal("reading:", err) } b := bytes.NewBuffer(d) var list []string for { line, err := b.ReadString('\n') if err == io.EOF { break } if !strings.Contains(line, `"`) { continue } i := strings.Index(line, `"`) line = line[i+1:] i = strings.Index(line, `"`) line = line[:i] list = append(list, line) } // generate package file names.go fmt.Print(`package cap /* ** DO NOT EDIT THIS FILE. IT WAS AUTO-GENERATED BY LIBCAP'S GO BUILDER (mknames.go) ** */ // NamedCount holds the number of capability values with official // names known at the time this libcap/cap version, was released. The // "../libcap/cap" package is fully able to manipulate higher numbered // capability values by numerical value. However, if you find // cap.NamedCount < cap.MaxBits(), it is probably time to upgrade this // package on your system. // // FWIW the userspace tool '/sbin/capsh' also contains a runtime check // for the condition that libcap is behind the running kernel in this // way. const NamedCount = `, len(list), ` // CHOWN etc., are the named capability values of the Linux // kernel. The canonical source for each name is the // "uapi/linux/capabilities.h" file. Some values may not be available // (yet) where the kernel is older. The actual number of capabities // supported by the running kernel can be obtained using the // cap.MaxBits() function. const ( `) bits := make(map[string]string) for i, name := range list { doc := fmt.Sprintf("%s/%d.txt", *text, i) content, err := ioutil.ReadFile(doc) if err != nil { log.Fatalf("filed to read %q: %v", doc, err) } detail := strings.Split(strings.Replace(string(content), "CAP_", "cap.", -1), "\n") if i != 0 { fmt.Println() } v := strings.ToUpper(strings.TrimPrefix(name, "cap_")) for j, line := range detail { preamble := "" offset := 0 if j == 0 { if !strings.HasPrefix(line, "Allows ") { log.Fatalf("line should begin \"Allows \": got %s:%d:%q", doc, j, line) } preamble = fmt.Sprint(v, " a") offset = 1 } if len(line) != 0 || j != len(detail)-1 { fmt.Printf(" // %s%s\n", preamble, line[offset:]) } } bits[name] = v if i == 0 { fmt.Println(v, " Value = iota") } else { fmt.Println(v) } } fmt.Print(`) var names = map[Value]string{ `) for _, name := range list { fmt.Printf("%s: %q,\n", bits[name], name) } fmt.Print(`} var bits = map[string]Value { `) for _, name := range list { fmt.Printf("%q: %s,\n", name, bits[name]) } fmt.Println(`}`) }