github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/tools/syz-testbed/checkout.go (about) 1 // Copyright 2021 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 package main 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "log" 10 "path/filepath" 11 "sync" 12 "time" 13 14 syz_instance "github.com/google/syzkaller/pkg/instance" 15 "github.com/google/syzkaller/pkg/mgrconfig" 16 "github.com/google/syzkaller/pkg/osutil" 17 "github.com/google/syzkaller/pkg/report" 18 "github.com/google/syzkaller/pkg/tool" 19 "github.com/google/syzkaller/pkg/vcs" 20 ) 21 22 type Checkout struct { 23 Path string 24 Name string 25 26 ManagerConfig json.RawMessage 27 Running map[Instance]bool 28 Completed []RunResult 29 LastRunning time.Time 30 reporter *report.Reporter 31 mu sync.Mutex 32 } 33 34 func (checkout *Checkout) GetReporter() *report.Reporter { 35 checkout.mu.Lock() 36 defer checkout.mu.Unlock() 37 if checkout.reporter == nil { 38 // Unfortunately, we have no other choice but to parse the config to use our own parser. 39 // TODO: add some tool to syzkaller that would just parse logs and then execute it here? 40 mgrCfg, err := mgrconfig.LoadPartialData(checkout.ManagerConfig) 41 if err != nil { 42 tool.Failf("failed to parse mgr config for %s: %s", checkout.Name, err) 43 } 44 checkout.reporter, err = report.NewReporter(mgrCfg) 45 if err != nil { 46 tool.Failf("failed to get reporter for %s: %s", checkout.Name, err) 47 } 48 } 49 return checkout.reporter 50 } 51 52 func (checkout *Checkout) AddRunning(instance Instance) { 53 checkout.mu.Lock() 54 defer checkout.mu.Unlock() 55 checkout.Running[instance] = true 56 checkout.LastRunning = time.Now() 57 } 58 59 func (checkout *Checkout) ArchiveInstance(instance Instance) error { 60 checkout.mu.Lock() 61 defer checkout.mu.Unlock() 62 result, err := instance.FetchResult() 63 if err != nil { 64 return err 65 } 66 checkout.Completed = append(checkout.Completed, result) 67 delete(checkout.Running, instance) 68 return nil 69 } 70 71 func (checkout *Checkout) GetRunningResults() []RunResult { 72 checkout.mu.Lock() 73 defer checkout.mu.Unlock() 74 running := []RunResult{} 75 for instance := range checkout.Running { 76 result, err := instance.FetchResult() 77 if err == nil { 78 running = append(running, result) 79 } 80 } 81 return running 82 } 83 84 func (checkout *Checkout) GetCompletedResults() []RunResult { 85 checkout.mu.Lock() 86 defer checkout.mu.Unlock() 87 return append([]RunResult{}, checkout.Completed...) 88 } 89 90 func (ctx *TestbedContext) NewCheckout(config *CheckoutConfig, mgrConfig json.RawMessage) (*Checkout, error) { 91 checkout := &Checkout{ 92 Name: config.Name, 93 Path: filepath.Join(ctx.Config.Workdir, "checkouts", config.Name), 94 ManagerConfig: mgrConfig, 95 Running: make(map[Instance]bool), 96 } 97 log.Printf("[%s] Checking out", checkout.Name) 98 if osutil.IsExist(checkout.Path) { 99 return nil, fmt.Errorf("path %s already exists", checkout.Path) 100 } 101 repo := vcs.NewSyzkallerRepo(checkout.Path) 102 commit, err := repo.Poll(config.Repo, config.Branch) 103 if err != nil { 104 return nil, fmt.Errorf("failed to checkout %s (%s): %w", config.Repo, config.Branch, err) 105 } 106 log.Printf("[%s] Done. Latest commit: %s", checkout.Name, commit) 107 log.Printf("[%s] Building", checkout.Name) 108 if _, err := osutil.RunCmd(time.Hour, checkout.Path, syz_instance.MakeBin); err != nil { 109 return nil, fmt.Errorf("[%s] Make failed: %w", checkout.Name, err) 110 } 111 return checkout, nil 112 }