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  }