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