Correct toolchain and kernel headers detection

cos-gpu-installer:v2 used to detect whether
/build/cos-tools is empty to find if toolchain
has already been installed. However, newer versions
of the installer require toolchain and kernel headers
to link GPU drivers. That directory will not be empty
if only one of toolchain and kernel headers exist.
In that case, installation will fail.

This CL changes the way installer detects the
required parts. The installer now detects and
installs toolchain and kernel headers separately. If
only one of the two is present, the installer will go
on to download and install the other one.

BUG=b/214429381

Change-Id: I5ee2af99b2bf48d451b7df5a5cba1dc2f2c32b3a
Reviewed-on: https://cos-review.googlesource.com/c/cos/tools/+/27760
Reviewed-by: Robert Kolchmeyer <rkolchmeyer@google.com>
Cloud-Build: GCB Service account <228075978874@cloudbuild.gserviceaccount.com>
Tested-by: He Gao <hegao@google.com>
diff --git a/src/pkg/cos/cos.go b/src/pkg/cos/cos.go
index e751e05..ff32f11 100644
--- a/src/pkg/cos/cos.go
+++ b/src/pkg/cos/cos.go
@@ -16,8 +16,10 @@
 )
 
 const (
-	espPartition = "/dev/sda12"
-	utsFilepath  = "include/generated/utsrelease.h"
+	espPartition      = "/dev/sda12"
+	utsFilepath       = "include/generated/utsrelease.h"
+	toolchainBinPath  = "bin"
+	kernelHeadersPath = "usr/src/linux-headers*"
 )
 
 var (
@@ -73,21 +75,36 @@
 	if err := os.MkdirAll(destDir, 0755); err != nil {
 		return errors.Wrapf(err, "failed to create dir %s", destDir)
 	}
+	foundToolchain, foundKernelHeaders := false, false
 	if empty, _ := utils.IsDirEmpty(destDir); !empty {
-		log.Info("Found existing toolchain. Skipping download and installation")
+		if _, err := os.Stat(filepath.Join(destDir, toolchainBinPath)); err == nil {
+			foundToolchain = true
+		}
+		if dirs, err := filepath.Glob(filepath.Join(destDir, kernelHeadersPath)); err == nil && len(dirs) > 0 {
+			foundKernelHeaders = true
+		}
+	}
+
+	if foundToolchain {
+		log.Info("Found existing toolchain. Skipping download and installation.")
 	} else {
 		if err := downloader.DownloadToolchain(destDir); err != nil {
 			return errors.Wrap(err, "failed to download toolchain")
 		}
-		if err := downloader.DownloadKernelHeaders(destDir); err != nil {
-			return fmt.Errorf("failed to download kernel headers: %v", err)
-		}
-
 		log.Info("Unpacking toolchain...")
 		if err := exec.Command("tar", "xf", filepath.Join(destDir, toolchainArchive), "-C", destDir).Run(); err != nil {
 			return errors.Wrap(err, "failed to extract toolchain archive tarball")
 		}
 		log.Info("Done unpacking toolchain")
+	}
+
+	if foundKernelHeaders {
+		log.Info("Found existing kernel headers. Skipping download and installation.")
+
+	} else {
+		if err := downloader.DownloadKernelHeaders(destDir); err != nil {
+			return fmt.Errorf("failed to download kernel headers: %v", err)
+		}
 		log.Info("Unpacking kernel headers...")
 		if err := exec.Command("tar", "xf", filepath.Join(destDir, kernelHeaders), "-C", destDir).Run(); err != nil {
 			return fmt.Errorf("failed to extract kernel headers: %v", err)