blob: c42a7fc6ca33a16d0ae82c96bb6222bcb572a5d4 [file] [log] [blame] [edit]
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"context"
"flag"
"fmt"
"os"
"path/filepath"
"cloud.google.com/go/storage"
"github.com/google/subcommands"
"cos.googlesource.com/cos/tools.git/src/pkg/cos"
"cos.googlesource.com/cos/tools.git/src/pkg/cosboot"
)
type showCmd struct{}
func (*showCmd) Name() string {
return "show"
}
func (*showCmd) Synopsis() string {
return "Show kernel arguments that will be used on the next boot."
}
func (*showCmd) Usage() string {
return "show [disk image]\n"
}
func (*showCmd) SetFlags(f *flag.FlagSet) {}
func (*showCmd) showForGRUBBoot(disk string) subcommands.ExitStatus {
cmdLine, err := cosboot.NextGRUBCmdLine(disk)
if err != nil {
fmt.Printf("Error reading next GRUB command line: %v\n", err)
return subcommands.ExitFailure
}
fmt.Println(cmdLine)
return subcommands.ExitSuccess
}
func downloadVmlinux(ctx context.Context, gcsClient *storage.Client, disk, outDir string) (string, error) {
var envReader *cos.EnvReader
if disk == "" {
var err error
envReader, err = cos.NewEnvReader("/")
if err != nil {
return "", err
}
} else {
var err error
envReader, err = cos.NewEnvReaderFromLocalDisk(disk)
if err != nil {
return "", err
}
}
dl := cos.NewGCSDownloader(gcsClient, envReader, "", "", "", "")
if err := dl.DownloadArtifact(ctx, outDir, "vmlinux"); err != nil {
return "", err
}
return filepath.Join(outDir, "vmlinux"), nil
}
func (*showCmd) showForUKIBoot(ctx context.Context, disk, vmlinuxPath string) subcommands.ExitStatus {
if vmlinuxPath == "" {
gcsClient, err := storage.NewClient(ctx)
if err != nil {
fmt.Printf("Error creating GCS client: %v\n", err)
return subcommands.ExitFailure
}
tmpDir, err := os.MkdirTemp("", "cos-kernel-args")
if err != nil {
fmt.Printf("Error creating tempdir: %v\n", err)
return subcommands.ExitFailure
}
defer os.RemoveAll(tmpDir)
vmlinuxPath, err = downloadVmlinux(ctx, gcsClient, disk, tmpDir)
if err != nil {
fmt.Printf("Could not download vmlinux and one was not provided: %v\n", err)
return subcommands.ExitFailure
}
}
cmdLine, err := cosboot.NextUKICmdLine(disk, vmlinuxPath)
if err != nil {
fmt.Printf("Error reading next UKI command line: %v\n", err)
return subcommands.ExitFailure
}
fmt.Println(cmdLine)
return subcommands.ExitSuccess
}
func (c *showCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
disk := ""
if f.NArg() > 0 {
disk = f.Arg(0)
}
bootPath, err := cosboot.DiskBootPath(disk)
if err != nil {
fmt.Printf("Error identifying boot path: %v\n", err)
return subcommands.ExitFailure
}
if bootPath == cosboot.GRUBBoot {
return c.showForGRUBBoot(disk)
} else if bootPath == cosboot.UKI {
return c.showForUKIBoot(context.Background(), disk, *vmlinuxPath)
} else {
// This should never happen
fmt.Println("Could not identify boot path")
return subcommands.ExitFailure
}
}