github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/cmd/snap-preseed/main.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2019 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package main
    21  
    22  import (
    23  	"fmt"
    24  	"io"
    25  	"os"
    26  	"path/filepath"
    27  
    28  	"github.com/jessevdk/go-flags"
    29  )
    30  
    31  const (
    32  	shortHelp = "Prerun the first boot seeding of snaps in an image filesystem chroot with a snapd seed."
    33  	longHelp  = `
    34  The snap-preseed command takes a directory containing an image, including seed
    35  snaps (at /var/lib/snapd/seed), and runs through the snapd first-boot process
    36  up to hook execution. No boot actions unrelated to snapd are performed.
    37  It creates systemd units for seeded snaps, makes any connections, and generates
    38  security profiles. The image is updated and consequently optimised to reduce
    39  first-boot startup time`
    40  )
    41  
    42  type options struct {
    43  	Reset bool `long:"reset"`
    44  }
    45  
    46  var (
    47  	osGetuid           = os.Getuid
    48  	Stdout   io.Writer = os.Stdout
    49  	Stderr   io.Writer = os.Stderr
    50  
    51  	opts options
    52  )
    53  
    54  func Parser() *flags.Parser {
    55  	opts = options{}
    56  	parser := flags.NewParser(&opts, flags.HelpFlag|flags.PassDoubleDash|flags.PassAfterNonOption)
    57  	parser.ShortDescription = shortHelp
    58  	parser.LongDescription = longHelp
    59  	return parser
    60  }
    61  
    62  func main() {
    63  	parser := Parser()
    64  	if err := run(parser, os.Args[1:]); err != nil {
    65  		fmt.Fprintf(Stderr, "error: %v\n", err)
    66  		os.Exit(1)
    67  	}
    68  }
    69  
    70  func run(parser *flags.Parser, args []string) error {
    71  	if osGetuid() != 0 {
    72  		return fmt.Errorf("must be run as root")
    73  	}
    74  
    75  	rest, err := parser.ParseArgs(args)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	if len(rest) == 0 {
    81  		return fmt.Errorf("need chroot path as argument")
    82  	}
    83  
    84  	chrootDir, err := filepath.Abs(rest[0])
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	// safety check
    90  	if chrootDir == "/" {
    91  		return fmt.Errorf("cannot run snap-preseed against /")
    92  	}
    93  
    94  	if opts.Reset {
    95  		return resetPreseededChroot(chrootDir)
    96  	}
    97  
    98  	if err := checkChroot(chrootDir); err != nil {
    99  		return err
   100  	}
   101  
   102  	targetSnapd, cleanup, err := prepareChroot(chrootDir)
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	// executing inside the chroot
   108  	err = runPreseedMode(chrootDir, targetSnapd)
   109  	cleanup()
   110  	return err
   111  }