blob: 8119154a5051c076dc6dc6b22b5d747ba478307d [file] [log] [blame] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package dut
import (
"context"
"encoding/gob"
"errors"
"fmt"
"log"
"os"
"time"
"chromium.googlesource.com/chromiumos/platform/dev-util.git/contrib/fflash/internal/logging"
"chromium.googlesource.com/chromiumos/platform/dev-util.git/contrib/fflash/internal/progress"
)
func Main() error {
var r Request
if err := gob.NewDecoder(os.Stdin).Decode(&r); err != nil {
return fmt.Errorf("cannot decode flash request: %w", err)
}
logging.SetUp(time.Now().Add(-r.ElapsedTimeWhenSent))
log.SetPrefix("[dut-agent] ")
ctx := context.Background()
partState, err := ActivePartitions(ctx)
if err != nil {
return fmt.Errorf("cannot get active partitions: %w", err)
}
log.Printf("active kernel/rootfs: %s, %s", partState.ActiveKernel(), partState.ActiveRootfs())
log.Printf("flashing to: %s, %s", partState.InactiveKernel(), partState.InactiveRootfs())
client, err := r.Client(ctx)
if err != nil {
return err
}
defer client.Close()
pr := progress.NewProgressReporter()
ch := make(chan error)
flashCtx, cancelFlash := context.WithCancel(ctx)
defer cancelFlash()
go func(rw *progress.ReportingWriter) {
ch <- r.Flash(flashCtx, client, rw, KernelImage, partState.InactiveKernel())
}(pr.NewWriter("kernel"))
go func(rw *progress.ReportingWriter) {
ch <- r.Flash(flashCtx, client, rw, RootfsImage, partState.InactiveRootfs())
}(pr.NewWriter("rootfs"))
go func(rw *progress.ReportingWriter) {
ch <- r.FlashStateful(flashCtx, client, rw, r.ClobberStateful)
}(pr.NewWriter("stateful"))
var failed bool
completed := 0
ticker := time.NewTicker(time.Second)
for completed < 3 {
select {
case err := <-ch:
if err != nil {
failed = true
cancelFlash()
if !errors.Is(err, context.Canceled) {
log.Println(err)
}
}
completed += 1
case <-ticker.C:
log.Println("flash", pr.Report())
}
}
ticker.Stop()
if failed {
return fmt.Errorf("flash failed")
}
log.Println("flash", pr.Report())
log.Println("running postinst")
if err := RunPostinst(ctx, partState.InactiveRootfs()); err != nil {
return fmt.Errorf("postinst failed: %w", err)
}
result := &Result{}
if r.DisableRootfsVerification {
log.Println("disabling rootfs verification")
if err := DisableRootfsVerification(ctx, partState.InactiveKernelNum); err != nil {
log.Printf("disable rootfs verification failed (will retry after reboot): %s", err)
result.RetryDisableRootfsVerification = true
}
}
if r.ClearTpmOwner {
log.Println("clearing tpm owner")
if err := ClearTpmOwner(ctx); err != nil {
log.Printf("clear tpm owner request failed (will retry after reboot): %s", err)
result.RetryClearTpmOwner = true
}
}
if err := gob.NewEncoder(os.Stdout).Encode(result); err != nil {
return fmt.Errorf("failed to encode result: %w", err)
}
return nil
}