// Copyright 2016 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// syz-crush replays crash log on multiple VMs. Usage:
//   syz-crush -config=config.file execution.log
// Intended for reproduction of particularly elusive crashes.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"sync"
	"sync/atomic"
	"time"

	"github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/pkg/report"
	"github.com/google/syzkaller/prog"
	"github.com/google/syzkaller/syz-manager/mgrconfig"
	"github.com/google/syzkaller/vm"
)

var (
	flagConfig = flag.String("config", "", "configuration file")
)

func main() {
	flag.Parse()
	cfg, err := mgrconfig.LoadFile(*flagConfig)
	if err != nil {
		log.Fatalf("%v", err)
	}
	if len(flag.Args()) != 1 {
		log.Fatalf("usage: syz-crush -config=config.file execution.log")
	}
	if _, err := prog.GetTarget(cfg.TargetOS, cfg.TargetArch); err != nil {
		log.Fatalf("%v", err)
	}
	env := mgrconfig.CreateVMEnv(cfg, false)
	vmPool, err := vm.Create(cfg.Type, env)
	if err != nil {
		log.Fatalf("%v", err)
	}
	reporter, err := report.NewReporter(cfg.TargetOS, cfg.Kernel_Src,
		filepath.Dir(cfg.Vmlinux), nil, cfg.ParsedIgnores)
	if err != nil {
		log.Fatalf("%v", err)
	}

	log.Logf(0, "booting test machines...")
	var shutdown uint32
	var wg sync.WaitGroup
	wg.Add(vmPool.Count() + 1)
	for i := 0; i < vmPool.Count(); i++ {
		i := i
		go func() {
			defer wg.Done()
			for {
				runInstance(cfg, reporter, vmPool, i)
				if atomic.LoadUint32(&shutdown) != 0 {
					break
				}
			}
		}()
	}

	shutdownC := make(chan struct{})
	osutil.HandleInterrupts(shutdownC)
	go func() {
		<-shutdownC
		wg.Done()
		atomic.StoreUint32(&shutdown, 1)
	}()
	wg.Wait()
}

func runInstance(cfg *mgrconfig.Config, reporter report.Reporter, vmPool *vm.Pool, index int) {
	inst, err := vmPool.Create(index)
	if err != nil {
		log.Logf(0, "failed to create instance: %v", err)
		return
	}
	defer inst.Close()

	execprogBin, err := inst.Copy(cfg.SyzExecprogBin)
	if err != nil {
		log.Logf(0, "failed to copy execprog: %v", err)
		return
	}
	executorBin, err := inst.Copy(cfg.SyzExecutorBin)
	if err != nil {
		log.Logf(0, "failed to copy executor: %v", err)
		return
	}
	logFile, err := inst.Copy(flag.Args()[0])
	if err != nil {
		log.Logf(0, "failed to copy log: %v", err)
		return
	}

	cmd := fmt.Sprintf("%v -executor=%v -repeat=0 -procs=%v -cover=0 -sandbox=%v %v",
		execprogBin, executorBin, cfg.Procs, cfg.Sandbox, logFile)
	outc, errc, err := inst.Run(time.Hour, nil, cmd)
	if err != nil {
		log.Logf(0, "failed to run execprog: %v", err)
		return
	}

	log.Logf(0, "vm-%v: crushing...", index)
	rep := vm.MonitorExecution(outc, errc, reporter, false)
	if rep == nil {
		// This is the only "OK" outcome.
		log.Logf(0, "vm-%v: running long enough, restarting", index)
	} else {
		f, err := ioutil.TempFile(".", "syz-crush")
		if err != nil {
			log.Logf(0, "failed to create temp file: %v", err)
			return
		}
		defer f.Close()
		log.Logf(0, "vm-%v: crashed: %v, saving to %v", index, rep.Title, f.Name())
		f.Write(rep.Output)
	}
	return
}
