github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/gadget/install/content.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2019-2020 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 install
    21  
    22  import (
    23  	"fmt"
    24  	"os"
    25  	"path/filepath"
    26  	"strconv"
    27  
    28  	"github.com/snapcore/snapd/dirs"
    29  	"github.com/snapcore/snapd/gadget"
    30  	"github.com/snapcore/snapd/gadget/quantity"
    31  	"github.com/snapcore/snapd/logger"
    32  	"github.com/snapcore/snapd/osutil/mkfs"
    33  )
    34  
    35  var contentMountpoint string
    36  
    37  func init() {
    38  	contentMountpoint = filepath.Join(dirs.SnapRunDir, "gadget-install")
    39  }
    40  
    41  // makeFilesystem creates a filesystem on the on-disk structure, according
    42  // to the filesystem type defined in the gadget. If sectorSize is specified,
    43  // that sector size is used when creating the filesystem, otherwise if it is
    44  // zero, automatic values are used instead.
    45  func makeFilesystem(ds *gadget.OnDiskStructure, sectorSize quantity.Size) error {
    46  	if ds.HasFilesystem() {
    47  		logger.Debugf("create %s filesystem on %s with label %q", ds.VolumeStructure.Filesystem, ds.Node, ds.VolumeStructure.Label)
    48  		if err := mkfs.Make(ds.VolumeStructure.Filesystem, ds.Node, ds.VolumeStructure.Label, ds.Size, sectorSize); err != nil {
    49  			return err
    50  		}
    51  		if err := udevTrigger(ds.Node); err != nil {
    52  			return err
    53  		}
    54  	}
    55  	return nil
    56  }
    57  
    58  // writeContent populates the given on-disk structure, according to the contents
    59  // defined in the gadget.
    60  func writeContent(ds *gadget.OnDiskStructure, gadgetRoot string, observer gadget.ContentObserver) error {
    61  	switch {
    62  	case !ds.IsPartition():
    63  		return fmt.Errorf("cannot write non-partitions yet")
    64  	case !ds.HasFilesystem():
    65  		if err := writeNonFSContent(ds, gadgetRoot); err != nil {
    66  			return err
    67  		}
    68  	case ds.HasFilesystem():
    69  		if err := writeFilesystemContent(ds, gadgetRoot, observer); err != nil {
    70  			return err
    71  		}
    72  	}
    73  
    74  	return nil
    75  }
    76  
    77  // mountFilesystem mounts the on-disk structure filesystem under the given base
    78  // directory, using the label defined in the gadget as the mount point name.
    79  func mountFilesystem(ds *gadget.OnDiskStructure, baseMntPoint string) error {
    80  	if !ds.HasFilesystem() {
    81  		return fmt.Errorf("cannot mount a partition with no filesystem")
    82  	}
    83  	if ds.Label == "" {
    84  		return fmt.Errorf("cannot mount a filesystem with no label")
    85  	}
    86  
    87  	mountpoint := filepath.Join(baseMntPoint, ds.Label)
    88  	if err := os.MkdirAll(mountpoint, 0755); err != nil {
    89  		return fmt.Errorf("cannot create mountpoint: %v", err)
    90  	}
    91  	if err := sysMount(ds.Node, mountpoint, ds.Filesystem, 0, ""); err != nil {
    92  		return fmt.Errorf("cannot mount filesystem %q at %q: %v", ds.Node, mountpoint, err)
    93  	}
    94  
    95  	return nil
    96  }
    97  
    98  func writeFilesystemContent(ds *gadget.OnDiskStructure, gadgetRoot string, observer gadget.ContentObserver) (err error) {
    99  	mountpoint := filepath.Join(contentMountpoint, strconv.Itoa(ds.Index))
   100  	if err := os.MkdirAll(mountpoint, 0755); err != nil {
   101  		return err
   102  	}
   103  
   104  	// temporarily mount the filesystem
   105  	if err := sysMount(ds.Node, mountpoint, ds.Filesystem, 0, ""); err != nil {
   106  		return fmt.Errorf("cannot mount filesystem %q at %q: %v", ds.Node, mountpoint, err)
   107  	}
   108  	defer func() {
   109  		errUnmount := sysUnmount(mountpoint, 0)
   110  		if err == nil {
   111  			err = errUnmount
   112  		}
   113  	}()
   114  	fs, err := gadget.NewMountedFilesystemWriter(&ds.LaidOutStructure, observer)
   115  	if err != nil {
   116  		return fmt.Errorf("cannot create filesystem image writer: %v", err)
   117  	}
   118  
   119  	var noFilesToPreserve []string
   120  	if err := fs.Write(mountpoint, noFilesToPreserve); err != nil {
   121  		return fmt.Errorf("cannot create filesystem image: %v", err)
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  func writeNonFSContent(ds *gadget.OnDiskStructure, gadgetRoot string) error {
   128  	f, err := os.OpenFile(ds.Node, os.O_RDWR, 0644)
   129  	if err != nil {
   130  		return fmt.Errorf("cannot write bare content for %q: %v", ds.Node, err)
   131  	}
   132  	defer f.Close()
   133  
   134  	// Laid out structures start relative to the beginning of the
   135  	// volume, shift the structure offsets to 0, so that it starts
   136  	// at the beginning of the partition
   137  	l := gadget.ShiftStructureTo(ds.LaidOutStructure, 0)
   138  	raw, err := gadget.NewRawStructureWriter(gadgetRoot, &l)
   139  	if err != nil {
   140  		return err
   141  	}
   142  	return raw.Write(f)
   143  }