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