github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/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  	// for SanitizePlugsSlots
    31  	"github.com/snapcore/snapd/interfaces/builtin"
    32  	"github.com/snapcore/snapd/snap"
    33  )
    34  
    35  const (
    36  	shortHelp = "Prerun the first boot seeding of snaps in an image filesystem chroot with a snapd seed."
    37  	longHelp  = `
    38  The snap-preseed command takes a directory containing an image, including seed
    39  snaps (at /var/lib/snapd/seed), and runs through the snapd first-boot process
    40  up to hook execution. No boot actions unrelated to snapd are performed.
    41  It creates systemd units for seeded snaps, makes any connections, and generates
    42  security profiles. The image is updated and consequently optimised to reduce
    43  first-boot startup time`
    44  )
    45  
    46  type options struct {
    47  	Reset bool `long:"reset"`
    48  }
    49  
    50  var (
    51  	osGetuid           = os.Getuid
    52  	Stdout   io.Writer = os.Stdout
    53  	Stderr   io.Writer = os.Stderr
    54  
    55  	opts options
    56  )
    57  
    58  func Parser() *flags.Parser {
    59  	opts = options{}
    60  	parser := flags.NewParser(&opts, flags.HelpFlag|flags.PassDoubleDash|flags.PassAfterNonOption)
    61  	parser.ShortDescription = shortHelp
    62  	parser.LongDescription = longHelp
    63  	return parser
    64  }
    65  
    66  func main() {
    67  	parser := Parser()
    68  	if err := run(parser, os.Args[1:]); err != nil {
    69  		fmt.Fprintf(Stderr, "error: %v\n", err)
    70  		os.Exit(1)
    71  	}
    72  }
    73  
    74  func run(parser *flags.Parser, args []string) error {
    75  	// real validation of plugs and slots; needs to be set
    76  	// for processing of seeds with gadget because of readInfo().
    77  	snap.SanitizePlugsSlots = builtin.SanitizePlugsSlots
    78  
    79  	if osGetuid() != 0 {
    80  		return fmt.Errorf("must be run as root")
    81  	}
    82  
    83  	rest, err := parser.ParseArgs(args)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	if len(rest) == 0 {
    89  		return fmt.Errorf("need chroot path as argument")
    90  	}
    91  
    92  	chrootDir, err := filepath.Abs(rest[0])
    93  	if err != nil {
    94  		return err
    95  	}
    96  
    97  	// safety check
    98  	if chrootDir == "/" {
    99  		return fmt.Errorf("cannot run snap-preseed against /")
   100  	}
   101  
   102  	if opts.Reset {
   103  		return resetPreseededChroot(chrootDir)
   104  	}
   105  
   106  	if err := checkChroot(chrootDir); err != nil {
   107  		return err
   108  	}
   109  
   110  	targetSnapd, cleanup, err := prepareChroot(chrootDir)
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	// executing inside the chroot
   116  	err = runPreseedMode(chrootDir, targetSnapd)
   117  	cleanup()
   118  	return err
   119  }