1// Copyright 2017 syzkaller project authors. All rights reserved.
2// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
3
4// syz-fmt re-formats sys files into standard form.
5package main
6
7import (
8	"bytes"
9	"fmt"
10	"io/ioutil"
11	"os"
12	"path/filepath"
13	"strings"
14
15	"github.com/google/syzkaller/pkg/ast"
16)
17
18func main() {
19	if len(os.Args) < 2 {
20		fmt.Fprintf(os.Stderr, "usage: syz-fmt files... or dirs...\n")
21		os.Exit(1)
22	}
23	for _, arg := range os.Args[1:] {
24		st, err := os.Stat(arg)
25		if err != nil {
26			fmt.Fprintf(os.Stderr, "failed to stat %v: %v\n", arg, err)
27			os.Exit(1)
28		}
29		if st.IsDir() {
30			files, err := ioutil.ReadDir(arg)
31			if err != nil {
32				fmt.Fprintf(os.Stderr, "failed to read dir %v: %v\n", arg, err)
33				os.Exit(1)
34			}
35			for _, file := range files {
36				if !strings.HasSuffix(file.Name(), ".txt") {
37					continue
38				}
39				processFile(filepath.Join(arg, file.Name()), file.Mode())
40			}
41		} else {
42			processFile(arg, st.Mode())
43		}
44	}
45}
46
47func processFile(file string, mode os.FileMode) {
48	data, err := ioutil.ReadFile(file)
49	if err != nil {
50		fmt.Fprintf(os.Stderr, "failed to read file %v: %v\n", file, err)
51		os.Exit(1)
52	}
53	desc := ast.Parse(data, filepath.Base(file), nil)
54	if desc == nil {
55		os.Exit(1)
56	}
57	formatted := ast.Format(desc)
58	if bytes.Equal(data, formatted) {
59		return
60	}
61	fmt.Printf("reformatting %v\n", file)
62	if err := os.Rename(file, file+"~"); err != nil {
63		fmt.Fprintf(os.Stderr, "%v\n", err)
64		os.Exit(1)
65	}
66	if err := ioutil.WriteFile(file, formatted, mode); err != nil {
67		fmt.Fprintf(os.Stderr, "%v\n", err)
68		os.Exit(1)
69	}
70}
71