• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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