You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

449 lines
9.7 KiB

  1. // Copyright (c) 2014, Google Inc.
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  14. package main
  15. import (
  16. "bufio"
  17. "errors"
  18. "flag"
  19. "fmt"
  20. "io"
  21. "os"
  22. "path/filepath"
  23. "sort"
  24. "strconv"
  25. "strings"
  26. "unicode"
  27. )
  28. // ssl.h reserves values 1000 and above for error codes corresponding to
  29. // alerts. If automatically assigned reason codes exceed this value, this script
  30. // will error. This must be kept in sync with SSL_AD_REASON_OFFSET in ssl.h.
  31. const reservedReasonCode = 1000
  32. var resetFlag *bool = flag.Bool("reset", false, "If true, ignore current assignments and reassign from scratch")
  33. func makeErrors(reset bool) error {
  34. topLevelPath, err := findToplevel()
  35. if err != nil {
  36. return err
  37. }
  38. dirName, err := os.Getwd()
  39. if err != nil {
  40. return err
  41. }
  42. lib := filepath.Base(dirName)
  43. headerPath := filepath.Join(topLevelPath, "include", "openssl", lib+".h")
  44. errDir := filepath.Join(topLevelPath, "crypto", "err")
  45. dataPath := filepath.Join(errDir, lib+".errordata")
  46. headerFile, err := os.Open(headerPath)
  47. if err != nil {
  48. if os.IsNotExist(err) {
  49. return fmt.Errorf("No header %s. Run in the right directory or touch the file.", headerPath)
  50. }
  51. return err
  52. }
  53. prefix := strings.ToUpper(lib)
  54. functions, reasons, err := parseHeader(prefix, headerFile)
  55. headerFile.Close()
  56. if reset {
  57. err = nil
  58. functions = make(map[string]int)
  59. // Retain any reason codes above reservedReasonCode.
  60. newReasons := make(map[string]int)
  61. for key, value := range reasons {
  62. if value >= reservedReasonCode {
  63. newReasons[key] = value
  64. }
  65. }
  66. reasons = newReasons
  67. }
  68. if err != nil {
  69. return err
  70. }
  71. dir, err := os.Open(".")
  72. if err != nil {
  73. return err
  74. }
  75. defer dir.Close()
  76. filenames, err := dir.Readdirnames(-1)
  77. if err != nil {
  78. return err
  79. }
  80. for _, name := range filenames {
  81. if !strings.HasSuffix(name, ".c") {
  82. continue
  83. }
  84. if err := addFunctionsAndReasons(functions, reasons, name, prefix); err != nil {
  85. return err
  86. }
  87. }
  88. assignNewValues(functions, -1)
  89. assignNewValues(reasons, reservedReasonCode)
  90. headerFile, err = os.Open(headerPath)
  91. if err != nil {
  92. return err
  93. }
  94. defer headerFile.Close()
  95. newHeaderFile, err := os.OpenFile(headerPath+".tmp", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
  96. if err != nil {
  97. return err
  98. }
  99. defer newHeaderFile.Close()
  100. if err := writeHeaderFile(newHeaderFile, headerFile, prefix, functions, reasons); err != nil {
  101. return err
  102. }
  103. os.Rename(headerPath+".tmp", headerPath)
  104. dataFile, err := os.OpenFile(dataPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
  105. if err != nil {
  106. return err
  107. }
  108. outputStrings(dataFile, lib, typeFunctions, functions)
  109. outputStrings(dataFile, lib, typeReasons, reasons)
  110. dataFile.Close()
  111. return nil
  112. }
  113. func findToplevel() (path string, err error) {
  114. path = ".."
  115. buildingPath := filepath.Join(path, "BUILDING")
  116. _, err = os.Stat(buildingPath)
  117. if err != nil && os.IsNotExist(err) {
  118. path = filepath.Join("..", path)
  119. buildingPath = filepath.Join(path, "BUILDING")
  120. _, err = os.Stat(buildingPath)
  121. }
  122. if err != nil {
  123. return "", errors.New("Cannot find BUILDING file at the top-level")
  124. }
  125. return path, nil
  126. }
  127. type assignment struct {
  128. key string
  129. value int
  130. }
  131. type assignmentsSlice []assignment
  132. func (a assignmentsSlice) Len() int {
  133. return len(a)
  134. }
  135. func (a assignmentsSlice) Less(i, j int) bool {
  136. return a[i].value < a[j].value
  137. }
  138. func (a assignmentsSlice) Swap(i, j int) {
  139. a[i], a[j] = a[j], a[i]
  140. }
  141. func outputAssignments(w io.Writer, assignments map[string]int) {
  142. var sorted assignmentsSlice
  143. for key, value := range assignments {
  144. sorted = append(sorted, assignment{key, value})
  145. }
  146. sort.Sort(sorted)
  147. for _, assignment := range sorted {
  148. fmt.Fprintf(w, "#define %s %d\n", assignment.key, assignment.value)
  149. }
  150. }
  151. func parseDefineLine(line, lib string) (typ int, key string, value int, ok bool) {
  152. if !strings.HasPrefix(line, "#define ") {
  153. return
  154. }
  155. fields := strings.Fields(line)
  156. if len(fields) != 3 {
  157. return
  158. }
  159. funcPrefix := lib + "_F_"
  160. reasonPrefix := lib + "_R_"
  161. key = fields[1]
  162. switch {
  163. case strings.HasPrefix(key, funcPrefix):
  164. typ = typeFunctions
  165. case strings.HasPrefix(key, reasonPrefix):
  166. typ = typeReasons
  167. default:
  168. return
  169. }
  170. var err error
  171. if value, err = strconv.Atoi(fields[2]); err != nil {
  172. return
  173. }
  174. ok = true
  175. return
  176. }
  177. func writeHeaderFile(w io.Writer, headerFile io.Reader, lib string, functions, reasons map[string]int) error {
  178. var last []byte
  179. var haveLast, sawDefine bool
  180. newLine := []byte("\n")
  181. scanner := bufio.NewScanner(headerFile)
  182. for scanner.Scan() {
  183. line := scanner.Text()
  184. _, _, _, ok := parseDefineLine(line, lib)
  185. if ok {
  186. sawDefine = true
  187. continue
  188. }
  189. if haveLast {
  190. w.Write(last)
  191. w.Write(newLine)
  192. }
  193. if len(line) > 0 || !sawDefine {
  194. last = []byte(line)
  195. haveLast = true
  196. } else {
  197. haveLast = false
  198. }
  199. sawDefine = false
  200. }
  201. if err := scanner.Err(); err != nil {
  202. return err
  203. }
  204. outputAssignments(w, functions)
  205. outputAssignments(w, reasons)
  206. w.Write(newLine)
  207. if haveLast {
  208. w.Write(last)
  209. w.Write(newLine)
  210. }
  211. return nil
  212. }
  213. const (
  214. typeFunctions = iota
  215. typeReasons
  216. )
  217. func outputStrings(w io.Writer, lib string, ty int, assignments map[string]int) {
  218. lib = strings.ToUpper(lib)
  219. prefixLen := len(lib + "_F_")
  220. keys := make([]string, 0, len(assignments))
  221. for key := range assignments {
  222. keys = append(keys, key)
  223. }
  224. sort.Strings(keys)
  225. for _, key := range keys {
  226. typeString := "function"
  227. if ty == typeReasons {
  228. typeString = "reason"
  229. }
  230. fmt.Fprintf(w, "%s,%s,%d,%s\n", lib, typeString, assignments[key], key[prefixLen:])
  231. }
  232. }
  233. func assignNewValues(assignments map[string]int, reserved int) {
  234. // Needs to be in sync with the reason limit in
  235. // |ERR_reason_error_string|.
  236. max := 99
  237. for _, value := range assignments {
  238. if reserved >= 0 && value >= reserved {
  239. continue
  240. }
  241. if value > max {
  242. max = value
  243. }
  244. }
  245. max++
  246. // Sort the keys, so this script is reproducible.
  247. keys := make([]string, 0, len(assignments))
  248. for key, value := range assignments {
  249. if value == -1 {
  250. keys = append(keys, key)
  251. }
  252. }
  253. sort.Strings(keys)
  254. for _, key := range keys {
  255. if reserved >= 0 && max >= reserved {
  256. // If this happens, try passing -reset. Otherwise bump
  257. // up reservedReasonCode.
  258. panic("Automatically-assigned values exceeded limit!")
  259. }
  260. assignments[key] = max
  261. max++
  262. }
  263. }
  264. func handleDeclareMacro(line, join, macroName string, m map[string]int) {
  265. if i := strings.Index(line, macroName); i >= 0 {
  266. contents := line[i+len(macroName):]
  267. if i := strings.Index(contents, ")"); i >= 0 {
  268. contents = contents[:i]
  269. args := strings.Split(contents, ",")
  270. for i := range args {
  271. args[i] = strings.TrimSpace(args[i])
  272. }
  273. if len(args) != 2 {
  274. panic("Bad macro line: " + line)
  275. }
  276. token := args[0] + join + args[1]
  277. if _, ok := m[token]; !ok {
  278. m[token] = -1
  279. }
  280. }
  281. }
  282. }
  283. func addFunctionsAndReasons(functions, reasons map[string]int, filename, prefix string) error {
  284. file, err := os.Open(filename)
  285. if err != nil {
  286. return err
  287. }
  288. defer file.Close()
  289. reasonPrefix := prefix + "_R_"
  290. var currentFunction string
  291. scanner := bufio.NewScanner(file)
  292. for scanner.Scan() {
  293. line := scanner.Text()
  294. if len(line) > 0 && unicode.IsLetter(rune(line[0])) {
  295. /* Function start */
  296. fields := strings.Fields(line)
  297. for _, field := range fields {
  298. if i := strings.Index(field, "("); i != -1 {
  299. f := field[:i]
  300. // The return type of some functions is
  301. // a macro that contains a "(".
  302. if f == "STACK_OF" {
  303. continue
  304. }
  305. currentFunction = f
  306. for len(currentFunction) > 0 && currentFunction[0] == '*' {
  307. currentFunction = currentFunction[1:]
  308. }
  309. break
  310. }
  311. }
  312. }
  313. // Do not include cross-module error lines.
  314. if strings.Contains(line, "OPENSSL_PUT_ERROR(" + prefix + ",") {
  315. functionToken := prefix + "_F_" + currentFunction
  316. if _, ok := functions[functionToken]; !ok {
  317. functions[functionToken] = -1
  318. }
  319. }
  320. handleDeclareMacro(line, "_R_", "OPENSSL_DECLARE_ERROR_REASON(", reasons)
  321. handleDeclareMacro(line, "_F_", "OPENSSL_DECLARE_ERROR_FUNCTION(", functions)
  322. for len(line) > 0 {
  323. i := strings.Index(line, prefix + "_")
  324. if i == -1 {
  325. break
  326. }
  327. line = line[i:]
  328. end := strings.IndexFunc(line, func(r rune) bool {
  329. return !(r == '_' || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9'))
  330. })
  331. if end == -1 {
  332. end = len(line)
  333. }
  334. var token string
  335. token, line = line[:end], line[end:]
  336. switch {
  337. case strings.HasPrefix(token, reasonPrefix):
  338. if _, ok := reasons[token]; !ok {
  339. reasons[token] = -1
  340. }
  341. }
  342. }
  343. }
  344. return scanner.Err()
  345. }
  346. func parseHeader(lib string, file io.Reader) (functions, reasons map[string]int, err error) {
  347. functions = make(map[string]int)
  348. reasons = make(map[string]int)
  349. scanner := bufio.NewScanner(file)
  350. for scanner.Scan() {
  351. typ, key, value, ok := parseDefineLine(scanner.Text(), lib)
  352. if !ok {
  353. continue
  354. }
  355. switch typ {
  356. case typeFunctions:
  357. functions[key] = value
  358. case typeReasons:
  359. reasons[key] = value
  360. default:
  361. panic("internal error")
  362. }
  363. }
  364. err = scanner.Err()
  365. return
  366. }
  367. func main() {
  368. flag.Parse()
  369. if err := makeErrors(*resetFlag); err != nil {
  370. fmt.Fprintf(os.Stderr, "%s\n", err)
  371. os.Exit(1)
  372. }
  373. }