blob: b3c90290e7ab090f950a7a8da12bb3a52be99aab [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This script updates //third_party/boringssl/src to point to the current revision at:
// https://boringssl.googlesource.com/boringssl/+/master
//
// It also updates the generated build files, Rust bindings, and subset of code used in Zircon.
package main
import (
"crypto/sha256"
"encoding/hex"
"errors"
"flag"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
var (
boring = flag.String("boring", "third_party/boringssl", "Path to repository")
commit = flag.String("commit", "origin/upstream/master", "Upstream commit-ish to check out")
fuchsia = flag.String("fuchsia", os.Getenv("FUCHSIA_DIR"), "Fuchsia root directory")
garnet = flag.String("garnet", "garnet/manifest", "Path to Garnet manifest directoy")
zircon = flag.String("zircon", "zircon/third_party/ulib/uboringssl", "Path to Zircon library")
skipBoring = flag.Bool("skip-boring", false, "Don't update upstream sources or build files")
skipRust = flag.Bool("skip-rust", false, "Don't update Rust bindings")
skipZircon = flag.Bool("skip-zircon", false, "Don't update Zircon's uboringssl library")
)
// These uboringssl files don't needed to be rolled from BoringSSL.
var skipped_files = map[string]bool{
"/BUILD.gn": true,
"/README.fuchsia.md": true,
"/rules.mk": true,
"/stack-note.S": true,
}
// Utility functions
func infof(msg string) {
log.Printf("[+] %s\n", msg)
}
func warnf(msg string) {
log.Printf("<!> %s\n", msg)
}
// Executes a command with the given |name| and |args| using |cwd| as the current working directory.
func run(cwd string, name string, args ...string) []byte {
cmd := exec.Command(name, args...)
if len(cwd) > 0 {
cmd.Dir = cwd
}
out, err := cmd.CombinedOutput()
if err != nil {
cmdline := strings.Join(append([]string{name}, args...), " ")
warnf("Error returned for '" + cmdline + "'")
warnf("Output: " + string(out))
log.Fatal(err)
}
return out
}
// Sha256Sum returns the hex-encoded SHA256 digest of a file
func sha256sum(path string) string {
file, err := os.Open(path)
if err != nil {
log.Fatal(err)
}
defer file.Close()
digest := sha256.New()
if _, err := io.Copy(digest, file); err != nil {
log.Fatal(err)
}
return hex.EncodeToString(digest.Sum(nil))
}
// Both the Zircon and third-party copies of BoringSSL have a README file that ends with the current
// upstream git revision. This function updates those files.
func updateReadMe(readmePath string) {
infof(" Updating README file...")
// Get the git revision
rev := run(filepath.Join(*boring, "src"), "git", "rev-list", "HEAD", "--max-count=1")
revlen := int64(len(rev))
rev[revlen-1] = '/'
// Open the README.fuchsia file
readme, err := os.OpenFile(readmePath, os.O_RDWR, 0644)
if err != nil {
log.Fatal(err)
}
defer readme.Close()
// Check that the file ends with a git URL
const urlbase string = "https://fuchsia.googlesource.com/third_party/boringssl/+/"
urllen := int64(len(urlbase))
url := make([]byte, urllen)
off := int64(0)
var bytes_read int
info, err := readme.Stat()
if err != nil {
log.Fatal(err)
}
if info.Size() > urllen+revlen {
off = info.Size() - (urllen + revlen + 1)
}
if bytes_read, err = readme.ReadAt(url, off); err != nil {
log.Fatal(err)
}
if int64(bytes_read) < urllen || urlbase != string(url) {
log.Fatal(readmePath + " does not end with a valid git URL.")
}
// Write the new git revision into the URL
if _, err = readme.Write(rev); err != nil {
log.Fatal(err)
}
}
// Pulls latest BoringSSL for upstream, and generates new build files
func updateBoring() {
src := filepath.Join(*boring, "src")
infof("Updating sources...")
run(src, "git", "fetch")
run(src, "git", "checkout", *commit)
updateReadMe(filepath.Join(*boring, "README.fuchsia"))
infof("Generating build files...")
run(*boring, "python", filepath.Join(src, "util", "generate_build_files.py"), "gn")
}
// Regenerates the Rust bindings
func updateRust() {
run("", filepath.Join(*boring, "rust/boringssl-sys/bindgen.sh"))
}
// To update Zircon's uboringssl library, we update the revision number in the README file and
// copy any files present in uboringssl that do not match their counterpart in BoringSSL
func updateZircon() {
updateReadMe(filepath.Join(*zircon, "README.fuchsia.md"))
infof(" Updating sources from BoringSSL...")
missing_files := map[string]bool{}
walker := func(zirconPath string, zxInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if zxInfo.IsDir() {
return nil
}
stem := zirconPath[len(*zircon):]
if skipped_files[stem] {
return nil
}
// Look for the matching file under boringssl or boringssl/src
boringPath := filepath.Join(*boring, stem)
if _, err = os.Stat(boringPath); os.IsNotExist(err) {
boringPath = filepath.Join(*boring, "src", stem)
}
if _, err = os.Stat(boringPath); os.IsNotExist(err) {
missing_files[stem] = true
}
// Copy files that have changed
if sha256sum(boringPath) != sha256sum(zirconPath) {
run(*fuchsia, "cp", boringPath, zirconPath)
}
return nil
}
if err := filepath.Walk(*zircon, walker); err != nil {
log.Fatal(err)
}
// Warn about missing files
if len(missing_files) != 0 {
warnf("ERROR: These files are missing from upstream:")
for file := range missing_files {
warnf(file)
}
log.Fatal("Please resolve these files and try again.")
}
}
// Main function
func main() {
flag.Parse()
if len(*fuchsia) == 0 {
log.Fatal(errors.New("FUCHSIA_DIR not set and --fuchsia not specified"))
}
*boring = filepath.Join(*fuchsia, *boring)
*zircon = filepath.Join(*fuchsia, *zircon)
if !*skipBoring {
infof("Updating BoringSSL from upstream...")
updateBoring()
infof("Done!")
infof("")
infof("To test, please run:")
infof(" $ fx set ... --preinstall garnet/packages/tests/boringssl")
infof(" $ fx build")
infof(" $ fx serve")
infof(" $ fx run-test boringssl_tests")
infof("If tests pass; commit the changes in " + *boring)
infof("Then, update the BoringSSL revisions in the internal integration repository.")
}
if !*skipRust {
infof("Updating Rust bindings...")
updateRust()
infof("Done!")
}
if !*skipZircon {
infof("Updating Zircon's uboringssl library...")
updateZircon()
infof("Done!")
infof("")
infof("To test, please run launch Zircon and run:")
infof(" > k ut prng")
infof(" > /boot/test/sys/crypto_test")
infof("If tests pass; commit the changes in " + *zircon)
}
infof("Finally, update the BoringSSL revisions in the internal integration repository.")
infof("You can use `" + *boring + "/check-integration`to verify the revisions.")
}