Skip to content

Commit c549ad3

Browse files
committed
sys-apps/ignition: Use new upstream patch
The patch was reworked to use partx which already is in the initrd and to have safety checks for disks in use.
1 parent 1e4ef96 commit c549ad3

7 files changed

+548
-68
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
From dde5942cd6b1157e80ad2e16c55d2337a3979aaf Mon Sep 17 00:00:00 2001
2+
From: Kai Lueke <kailuke@microsoft.com>
3+
Date: Mon, 20 Nov 2023 15:47:24 +0100
4+
Subject: [PATCH 1/3] disks: Refuse to modify disks/partitions in use
5+
6+
When a partition or the whole disk is in use, sgdisk should not execute
7+
the destructive operation.
8+
Add a check that errors out when a disk in use or a partition in use is
9+
to be destroyed.
10+
---
11+
internal/exec/stages/disks/partitions.go | 152 +++++++++++++++++++++++
12+
1 file changed, 152 insertions(+)
13+
14+
diff --git a/internal/exec/stages/disks/partitions.go b/internal/exec/stages/disks/partitions.go
15+
index 747f08dc..7c1bd272 100644
16+
--- a/internal/exec/stages/disks/partitions.go
17+
+++ b/internal/exec/stages/disks/partitions.go
18+
@@ -19,8 +19,12 @@
19+
package disks
20+
21+
import (
22+
+ "bufio"
23+
"errors"
24+
"fmt"
25+
+ "io/ioutil"
26+
+ "os"
27+
+ "path/filepath"
28+
"regexp"
29+
"sort"
30+
"strconv"
31+
@@ -317,11 +321,134 @@ func (p PartitionList) Swap(i, j int) {
32+
p[i], p[j] = p[j], p[i]
33+
}
34+
35+
+func blockDevHeld(blockDev string) (bool, error) {
36+
+ blockDevResolved, err := filepath.EvalSymlinks(blockDev)
37+
+ if err != nil {
38+
+ return false, fmt.Errorf("failed to resolve %q: %v", blockDev, err)
39+
+ }
40+
+ _, blockDevNode := filepath.Split(blockDevResolved)
41+
+
42+
+ holdersDir := fmt.Sprintf("/sys/class/block/%s/holders/", blockDevNode)
43+
+ entries, err := ioutil.ReadDir(holdersDir)
44+
+ if err != nil {
45+
+ return false, fmt.Errorf("failed to retrieve holders of %q: %v", blockDev, err)
46+
+ }
47+
+ return len(entries) > 0, nil
48+
+}
49+
+
50+
+func blockDevMounted(blockDev string) (bool, error) {
51+
+ blockDevResolved, err := filepath.EvalSymlinks(blockDev)
52+
+ if err != nil {
53+
+ return false, fmt.Errorf("failed to resolve %q: %v", blockDev, err)
54+
+ }
55+
+
56+
+ mounts, err := os.Open("/proc/mounts")
57+
+ if err != nil {
58+
+ return false, fmt.Errorf("failed to open mounts: %v", err)
59+
+ }
60+
+ scanner := bufio.NewScanner(mounts)
61+
+ for scanner.Scan() {
62+
+ mountSource := strings.Split(scanner.Text(), " ")[0]
63+
+ if strings.Contains(mountSource, "/") {
64+
+ mountSourceResolved, err := filepath.EvalSymlinks(mountSource)
65+
+ if err != nil {
66+
+ return false, fmt.Errorf("failed to resolve %q: %v", mountSource, err)
67+
+ }
68+
+ if mountSourceResolved == blockDevResolved {
69+
+ return true, nil
70+
+ }
71+
+ }
72+
+ }
73+
+ if err := scanner.Err(); err != nil {
74+
+ return false, fmt.Errorf("failed to check mounts for %q: %v", blockDev, err)
75+
+ }
76+
+ return false, nil
77+
+}
78+
+
79+
+func blockDevPartitions(blockDev string) ([]string, error) {
80+
+ blockDevResolved, err := filepath.EvalSymlinks(blockDev)
81+
+ if err != nil {
82+
+ return nil, fmt.Errorf("failed to resolve %q: %v", blockDev, err)
83+
+ }
84+
+ _, blockDevNode := filepath.Split(blockDevResolved)
85+
+
86+
+ // This also works for extended MBR partitions
87+
+ sysDir := fmt.Sprintf("/sys/class/block/%s/", blockDevNode)
88+
+ entries, err := ioutil.ReadDir(sysDir)
89+
+ if err != nil {
90+
+ return nil, fmt.Errorf("failed to retrieve sysfs entries of %q: %v", blockDev, err)
91+
+ }
92+
+ var partitions []string
93+
+ for _, entry := range entries {
94+
+ if strings.HasPrefix(entry.Name(), blockDevNode) {
95+
+ partitions = append(partitions, "/dev/"+entry.Name())
96+
+ }
97+
+ }
98+
+
99+
+ return partitions, nil
100+
+}
101+
+
102+
+func blockDevInUse(blockDev string) (bool, []string, error) {
103+
+ // Note: This ignores swap and LVM usage
104+
+ inUse := false
105+
+ held, err := blockDevHeld(blockDev)
106+
+ if err != nil {
107+
+ return false, nil, fmt.Errorf("failed to check if %q is held: %v", blockDev, err)
108+
+ }
109+
+ mounted, err := blockDevMounted(blockDev)
110+
+ if err != nil {
111+
+ return false, nil, fmt.Errorf("failed to check if %q is mounted: %v", blockDev, err)
112+
+ }
113+
+ inUse = held || mounted
114+
+ partitions, err := blockDevPartitions(blockDev)
115+
+ if err != nil {
116+
+ return false, nil, fmt.Errorf("failed to retrieve partitions of %q: %v", blockDev, err)
117+
+ }
118+
+ var activePartitions []string
119+
+ for _, partition := range partitions {
120+
+ held, err := blockDevHeld(partition)
121+
+ if err != nil {
122+
+ return false, nil, fmt.Errorf("failed to check if %q is held: %v", partition, err)
123+
+ }
124+
+ mounted, err := blockDevMounted(partition)
125+
+ if err != nil {
126+
+ return false, nil, fmt.Errorf("failed to check if %q is mounted: %v", partition, err)
127+
+ }
128+
+ if held || mounted {
129+
+ activePartitions = append(activePartitions, partition)
130+
+ inUse = true
131+
+ }
132+
+ }
133+
+ return inUse, activePartitions, nil
134+
+}
135+
+
136+
+func partitionNumberPrefix(blockDev string) (string, error) {
137+
+ blockDevResolved, err := filepath.EvalSymlinks(blockDev)
138+
+ if err != nil {
139+
+ return "", fmt.Errorf("failed to resolve %q: %v", blockDev, err)
140+
+ }
141+
+ lastChar := blockDevResolved[len(blockDevResolved)-1]
142+
+ if '0' <= lastChar && lastChar <= '9' {
143+
+ return "p", nil
144+
+ }
145+
+ return "", nil
146+
+}
147+
+
148+
// partitionDisk partitions devAlias according to the spec given by dev
149+
func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
150+
+ inUse, activeParts, err := blockDevInUse(devAlias)
151+
+ if err != nil {
152+
+ return fmt.Errorf("failed usage check on %q: %v", devAlias, err)
153+
+ }
154+
+ if inUse && len(activeParts) == 0 {
155+
+ return fmt.Errorf("refusing to operate on directly active disk %q", devAlias)
156+
+ }
157+
if cutil.IsTrue(dev.WipeTable) {
158+
op := sgdisk.Begin(s.Logger, devAlias)
159+
s.Logger.Info("wiping partition table requested on %q", devAlias)
160+
+ if len(activeParts) > 0 {
161+
+ return fmt.Errorf("refusing to wipe active disk %q", devAlias)
162+
+ }
163+
op.WipeTable(true)
164+
if err := op.Commit(); err != nil {
165+
return err
166+
@@ -338,6 +465,11 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
167+
return err
168+
}
169+
170+
+ blockDevResolved, err := filepath.EvalSymlinks(devAlias)
171+
+ if err != nil {
172+
+ return fmt.Errorf("failed to resolve %q: %v", devAlias, err)
173+
+ }
174+
+
175+
// get a list of parititions that have size and start 0 replaced with the real sizes
176+
// that would be used if all specified partitions were to be created anew.
177+
// Also calculate sectors for all of the start/size values.
178+
@@ -356,16 +488,30 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
179+
matches := exists && matchErr == nil
180+
wipeEntry := cutil.IsTrue(part.WipePartitionEntry)
181+
182+
+ var modification bool
183+
+ var partInUse bool
184+
+ for _, activePart := range activeParts {
185+
+ prefix, err := partitionNumberPrefix(blockDevResolved)
186+
+ if err != nil {
187+
+ return err
188+
+ }
189+
+ if activePart == fmt.Sprintf("%s%s%d", blockDevResolved, prefix, part.Number) {
190+
+ partInUse = true
191+
+ }
192+
+ }
193+
+
194+
// This is a translation of the matrix in the operator notes.
195+
switch {
196+
case !exists && !shouldExist:
197+
s.Logger.Info("partition %d specified as nonexistant and no partition was found. Success.", part.Number)
198+
case !exists && shouldExist:
199+
op.CreatePartition(part)
200+
+ modification = true
201+
case exists && !shouldExist && !wipeEntry:
202+
return fmt.Errorf("partition %d exists but is specified as nonexistant and wipePartitionEntry is false", part.Number)
203+
case exists && !shouldExist && wipeEntry:
204+
op.DeletePartition(part.Number)
205+
+ modification = true
206+
case exists && shouldExist && matches:
207+
s.Logger.Info("partition %d found with correct specifications", part.Number)
208+
case exists && shouldExist && !wipeEntry && !matches:
209+
@@ -378,6 +524,7 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
210+
part.Label = &info.Label
211+
part.StartSector = &info.StartSector
212+
op.CreatePartition(part)
213+
+ modification = true
214+
} else {
215+
return fmt.Errorf("Partition %d didn't match: %v", part.Number, matchErr)
216+
}
217+
@@ -385,10 +532,15 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
218+
s.Logger.Info("partition %d did not meet specifications, wiping partition entry and recreating", part.Number)
219+
op.DeletePartition(part.Number)
220+
op.CreatePartition(part)
221+
+ modification = true
222+
default:
223+
// unfortunatey, golang doesn't check that all cases are handled exhaustively
224+
return fmt.Errorf("Unreachable code reached when processing partition %d. golang--", part.Number)
225+
}
226+
+
227+
+ if partInUse && modification {
228+
+ return fmt.Errorf("refusing to modfiy active partition %d on %q", part.Number, devAlias)
229+
+ }
230+
}
231+
232+
if err := op.Commit(); err != nil {
233+
--
234+
2.42.0
235+

sdk_container/src/third_party/coreos-overlay/sys-apps/ignition/files/0022-sgdisk-Run-partprobe-after-partition-changes.patch

Lines changed: 0 additions & 67 deletions
This file was deleted.

0 commit comments

Comments
 (0)