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 }