github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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/metacubex/gvisor/pkg/state/pretty" 24 "github.com/metacubex/gvisor/pkg/state/statefile" 25 "github.com/metacubex/gvisor/runsc/cmd/util" 26 "github.com/metacubex/gvisor/runsc/flag" 27 ) 28 29 // Statefile implements subcommands.Command for the "statefile" command. 30 type Statefile struct { 31 list bool 32 get string 33 key string 34 output string 35 html bool 36 } 37 38 // Name implements subcommands.Command. 39 func (*Statefile) Name() string { 40 return "state" 41 } 42 43 // Synopsis implements subcommands.Command. 44 func (*Statefile) Synopsis() string { 45 return "shows information about a statefile" 46 } 47 48 // Usage implements subcommands.Command. 49 func (*Statefile) Usage() string { 50 return `statefile [flags] <statefile>` 51 } 52 53 // SetFlags implements subcommands.Command. 54 func (s *Statefile) SetFlags(f *flag.FlagSet) { 55 f.BoolVar(&s.list, "list", false, "lists the metdata in the statefile.") 56 f.StringVar(&s.get, "get", "", "extracts the given metadata key.") 57 f.StringVar(&s.key, "key", "", "the integrity key for the file.") 58 f.StringVar(&s.output, "output", "", "target to write the result.") 59 f.BoolVar(&s.html, "html", false, "outputs in HTML format.") 60 } 61 62 // Execute implements subcommands.Command.Execute. 63 func (s *Statefile) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcommands.ExitStatus { 64 // Check arguments. 65 if s.list && s.get != "" { 66 util.Fatalf("error: can't specify -list and -get simultaneously.") 67 } 68 69 // Setup output. 70 var output = os.Stdout // Default. 71 if s.output != "" { 72 f, err := os.OpenFile(s.output, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) 73 if err != nil { 74 util.Fatalf("error opening output: %v", err) 75 } 76 defer func() { 77 if err := f.Close(); err != nil { 78 util.Fatalf("error flushing output: %v", err) 79 } 80 }() 81 output = f 82 } 83 84 // Open the file. 85 if f.NArg() != 1 { 86 f.Usage() 87 return subcommands.ExitUsageError 88 } 89 input, err := os.Open(f.Arg(0)) 90 if err != nil { 91 util.Fatalf("error opening input: %v\n", err) 92 } 93 94 if s.html { 95 fmt.Fprintf(output, "<html><body>\n") 96 defer fmt.Fprintf(output, "</body></html>\n") 97 } 98 99 // Dump the full file? 100 if !s.list && s.get == "" { 101 var key []byte 102 if s.key != "" { 103 key = []byte(s.key) 104 } 105 rc, _, err := statefile.NewReader(input, key) 106 if err != nil { 107 util.Fatalf("error parsing statefile: %v", err) 108 } 109 if s.html { 110 if err := pretty.PrintHTML(output, rc); err != nil { 111 util.Fatalf("error printing state: %v", err) 112 } 113 } else { 114 if err := pretty.PrintText(output, rc); err != nil { 115 util.Fatalf("error printing state: %v", err) 116 } 117 } 118 return subcommands.ExitSuccess 119 } 120 121 // Load just the metadata. 122 metadata, err := statefile.MetadataUnsafe(input) 123 if err != nil { 124 util.Fatalf("error reading metadata: %v", err) 125 } 126 127 // Is it a single key? 128 if s.get != "" { 129 val, ok := metadata[s.get] 130 if !ok { 131 util.Fatalf("metadata key %s: not found", s.get) 132 } 133 fmt.Fprintf(output, "%s\n", val) 134 return subcommands.ExitSuccess 135 } 136 137 // List all keys. 138 if s.html { 139 fmt.Fprintf(output, " <ul>\n") 140 defer fmt.Fprintf(output, " </ul>\n") 141 } 142 for key := range metadata { 143 if s.html { 144 fmt.Fprintf(output, " <li>%s</li>\n", key) 145 } else { 146 fmt.Fprintf(output, "%s\n", key) 147 } 148 } 149 return subcommands.ExitSuccess 150 }