github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/runsc/cmd/statefile.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cmd 16 17 import ( 18 "context" 19 "fmt" 20 "os" 21 22 "github.com/google/subcommands" 23 "github.com/SagerNet/gvisor/pkg/state/pretty" 24 "github.com/SagerNet/gvisor/pkg/state/statefile" 25 "github.com/SagerNet/gvisor/runsc/flag" 26 ) 27 28 // Statefile implements subcommands.Command for the "statefile" command. 29 type Statefile struct { 30 list bool 31 get string 32 key string 33 output string 34 html bool 35 } 36 37 // Name implements subcommands.Command. 38 func (*Statefile) Name() string { 39 return "state" 40 } 41 42 // Synopsis implements subcommands.Command. 43 func (*Statefile) Synopsis() string { 44 return "shows information about a statefile" 45 } 46 47 // Usage implements subcommands.Command. 48 func (*Statefile) Usage() string { 49 return `statefile [flags] <statefile>` 50 } 51 52 // SetFlags implements subcommands.Command. 53 func (s *Statefile) SetFlags(f *flag.FlagSet) { 54 f.BoolVar(&s.list, "list", false, "lists the metdata in the statefile.") 55 f.StringVar(&s.get, "get", "", "extracts the given metadata key.") 56 f.StringVar(&s.key, "key", "", "the integrity key for the file.") 57 f.StringVar(&s.output, "output", "", "target to write the result.") 58 f.BoolVar(&s.html, "html", false, "outputs in HTML format.") 59 } 60 61 // Execute implements subcommands.Command.Execute. 62 func (s *Statefile) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { 63 // Check arguments. 64 if s.list && s.get != "" { 65 Fatalf("error: can't specify -list and -get simultaneously.") 66 } 67 68 // Setup output. 69 var output = os.Stdout // Default. 70 if s.output != "" { 71 f, err := os.OpenFile(s.output, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) 72 if err != nil { 73 Fatalf("error opening output: %v", err) 74 } 75 defer func() { 76 if err := f.Close(); err != nil { 77 Fatalf("error flushing output: %v", err) 78 } 79 }() 80 output = f 81 } 82 83 // Open the file. 84 if f.NArg() != 1 { 85 f.Usage() 86 return subcommands.ExitUsageError 87 } 88 input, err := os.Open(f.Arg(0)) 89 if err != nil { 90 Fatalf("error opening input: %v\n", err) 91 } 92 93 if s.html { 94 fmt.Fprintf(output, "<html><body>\n") 95 defer fmt.Fprintf(output, "</body></html>\n") 96 } 97 98 // Dump the full file? 99 if !s.list && s.get == "" { 100 var key []byte 101 if s.key != "" { 102 key = []byte(s.key) 103 } 104 rc, _, err := statefile.NewReader(input, key) 105 if err != nil { 106 Fatalf("error parsing statefile: %v", err) 107 } 108 if s.html { 109 if err := pretty.PrintHTML(output, rc); err != nil { 110 Fatalf("error printing state: %v", err) 111 } 112 } else { 113 if err := pretty.PrintText(output, rc); err != nil { 114 Fatalf("error printing state: %v", err) 115 } 116 } 117 return subcommands.ExitSuccess 118 } 119 120 // Load just the metadata. 121 metadata, err := statefile.MetadataUnsafe(input) 122 if err != nil { 123 Fatalf("error reading metadata: %v", err) 124 } 125 126 // Is it a single key? 127 if s.get != "" { 128 val, ok := metadata[s.get] 129 if !ok { 130 Fatalf("metadata key %s: not found", s.get) 131 } 132 fmt.Fprintf(output, "%s\n", val) 133 return subcommands.ExitSuccess 134 } 135 136 // List all keys. 137 if s.html { 138 fmt.Fprintf(output, " <ul>\n") 139 defer fmt.Fprintf(output, " </ul>\n") 140 } 141 for key := range metadata { 142 if s.html { 143 fmt.Fprintf(output, " <li>%s</li>\n", key) 144 } else { 145 fmt.Fprintf(output, "%s\n", key) 146 } 147 } 148 return subcommands.ExitSuccess 149 }