blob: ff072180d1adaee309822a9798324fca9f3109df [file] [log] [blame]
// 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(`}`)
}