Merge lp:~sergiusens/goget-ubuntu-touch/beBetter into lp:goget-ubuntu-touch
- beBetter
- Merge into trunk
Proposed by
Sergio Schvezov
Status: | Merged |
---|---|
Approved by: | John Lenton |
Approved revision: | 195 |
Merged at revision: | 183 |
Proposed branch: | lp:~sergiusens/goget-ubuntu-touch/beBetter |
Merge into: | lp:goget-ubuntu-touch |
Diff against target: |
833 lines (+282/-405) 5 files modified
diskimage/common.go (+232/-19) diskimage/core_grub.go (+8/-194) diskimage/core_uboot.go (+9/-181) diskimage/errors.go (+32/-0) ubuntu-device-flash/core.go (+1/-11) |
To merge this branch: | bzr merge lp:~sergiusens/goget-ubuntu-touch/beBetter |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
John Lenton (community) | Approve | ||
Michael Vogt (community) | Approve | ||
Review via email: mp+261804@code.launchpad.net |
Commit message
Remove code duplication and manage mounting/unmounting better
Description of the change
To post a comment you must log in.
- 187. By Sergio Schvezov
-
Revert uneeded func name change
Revision history for this message
Sergio Schvezov (sergiusens) : | # |
- 188. By Sergio Schvezov
-
Try to cleanly unmount on mount errors
- 189. By Sergio Schvezov
-
Message about not being able to remove basemount
- 190. By Sergio Schvezov
-
Use syscall sync
- 191. By Sergio Schvezov
-
Nicer error for unmounting
- 192. By Sergio Schvezov
-
Adding errors.go
- 193. By Sergio Schvezov
-
Mapping errors
- 194. By Sergio Schvezov
-
removing duplicate code for paths to mounts
- 195. By Sergio Schvezov
-
Cleanup moved
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'diskimage/common.go' | |||
2 | --- diskimage/common.go 2015-04-21 19:35:46 +0000 | |||
3 | +++ diskimage/common.go 2015-06-15 15:32:50 +0000 | |||
4 | @@ -8,6 +8,7 @@ | |||
5 | 8 | package diskimage | 8 | package diskimage |
6 | 9 | 9 | ||
7 | 10 | import ( | 10 | import ( |
8 | 11 | "bufio" | ||
9 | 11 | "errors" | 12 | "errors" |
10 | 12 | "fmt" | 13 | "fmt" |
11 | 13 | "io/ioutil" | 14 | "io/ioutil" |
12 | @@ -15,6 +16,7 @@ | |||
13 | 15 | "os/exec" | 16 | "os/exec" |
14 | 16 | "path/filepath" | 17 | "path/filepath" |
15 | 17 | "strings" | 18 | "strings" |
16 | 19 | "syscall" | ||
17 | 18 | ) | 20 | ) |
18 | 19 | 21 | ||
19 | 20 | // This program is free software: you can redistribute it and/or modify it | 22 | // This program is free software: you can redistribute it and/or modify it |
20 | @@ -37,6 +39,10 @@ | |||
21 | 37 | } | 39 | } |
22 | 38 | } | 40 | } |
23 | 39 | 41 | ||
24 | 42 | var ( | ||
25 | 43 | syscallSync = syscall.Sync | ||
26 | 44 | ) | ||
27 | 45 | |||
28 | 40 | type Image interface { | 46 | type Image interface { |
29 | 41 | Mount() error | 47 | Mount() error |
30 | 42 | Unmount() error | 48 | Unmount() error |
31 | @@ -149,40 +155,247 @@ | |||
32 | 149 | return strings.TrimSpace(string(out)), err | 155 | return strings.TrimSpace(string(out)), err |
33 | 150 | } | 156 | } |
34 | 151 | 157 | ||
37 | 152 | func mount(partitions []partition) (baseMount string, err error) { | 158 | // BaseImage implements the basic primitives to manage images. |
38 | 153 | baseMount, err = ioutil.TempDir(os.TempDir(), "diskimage") | 159 | type BaseImage struct { |
39 | 160 | baseMount string | ||
40 | 161 | hardware HardwareDescription | ||
41 | 162 | location string | ||
42 | 163 | oem OemDescription | ||
43 | 164 | parts []partition | ||
44 | 165 | partCount int | ||
45 | 166 | size int64 | ||
46 | 167 | } | ||
47 | 168 | |||
48 | 169 | // Mount mounts the image. This also maps the loop device. | ||
49 | 170 | func (img *BaseImage) Mount() error { | ||
50 | 171 | if err := img.Map(); err != nil { | ||
51 | 172 | return err | ||
52 | 173 | } | ||
53 | 174 | |||
54 | 175 | baseMount, err := ioutil.TempDir(os.TempDir(), "diskimage") | ||
55 | 154 | if err != nil { | 176 | if err != nil { |
62 | 155 | return "", err | 177 | return err |
57 | 156 | } | ||
58 | 157 | |||
59 | 158 | // We change the mode so snappy can unpack as non root | ||
60 | 159 | if err := os.Chmod(baseMount, 0755); err != nil { | ||
61 | 160 | return "", err | ||
63 | 161 | } | 178 | } |
64 | 162 | 179 | ||
65 | 163 | //Remove Mountpoint if we fail along the way | 180 | //Remove Mountpoint if we fail along the way |
66 | 164 | defer func() { | 181 | defer func() { |
67 | 165 | if err != nil { | 182 | if err != nil { |
69 | 166 | os.Remove(baseMount) | 183 | if err := os.Remove(baseMount); err != nil { |
70 | 184 | fmt.Println("WARNING: cannot remove", baseMount, "due to", err) | ||
71 | 185 | } | ||
72 | 167 | } | 186 | } |
73 | 168 | }() | 187 | }() |
74 | 169 | 188 | ||
76 | 170 | for _, part := range partitions { | 189 | // We change the mode so snappy can unpack as non root |
77 | 190 | if err := os.Chmod(baseMount, 0755); err != nil { | ||
78 | 191 | return err | ||
79 | 192 | } | ||
80 | 193 | |||
81 | 194 | for _, part := range img.parts { | ||
82 | 171 | if part.fs == fsNone { | 195 | if part.fs == fsNone { |
83 | 172 | continue | 196 | continue |
84 | 173 | } | 197 | } |
85 | 174 | 198 | ||
86 | 175 | mountpoint := filepath.Join(baseMount, string(part.dir)) | 199 | mountpoint := filepath.Join(baseMount, string(part.dir)) |
87 | 176 | if err := os.MkdirAll(mountpoint, 0755); err != nil { | 200 | if err := os.MkdirAll(mountpoint, 0755); err != nil { |
97 | 177 | return "", err | 201 | return err |
98 | 178 | } | 202 | } |
99 | 179 | if out, err := exec.Command("mount", filepath.Join("/dev/mapper", part.loop), mountpoint).CombinedOutput(); err != nil { | 203 | |
100 | 180 | return "", fmt.Errorf("unable to mount dir to create system image: %s", out) | 204 | dev := filepath.Join("/dev/mapper", part.loop) |
101 | 181 | } | 205 | printOut("Mounting", dev, part.fs, "to", mountpoint) |
102 | 182 | } | 206 | if out, errMount := exec.Command("mount", filepath.Join("/dev/mapper", part.loop), mountpoint).CombinedOutput(); errMount != nil { |
103 | 183 | 207 | return ErrMount{dev: dev, mountpoint: mountpoint, fs: part.fs, out: out} | |
104 | 184 | return baseMount, nil | 208 | } |
105 | 185 | 209 | // this is cleanup in case one of the mounts fail | |
106 | 210 | defer func() { | ||
107 | 211 | if err != nil { | ||
108 | 212 | if err := exec.Command("umount", mountpoint).Run(); err != nil { | ||
109 | 213 | fmt.Println("WARNING:", mountpoint, "could not be unmounted") | ||
110 | 214 | return | ||
111 | 215 | } | ||
112 | 216 | |||
113 | 217 | if err := os.Remove(mountpoint); err != nil { | ||
114 | 218 | fmt.Println("WARNING: could not remove ", mountpoint) | ||
115 | 219 | } | ||
116 | 220 | } | ||
117 | 221 | }() | ||
118 | 222 | } | ||
119 | 223 | img.baseMount = baseMount | ||
120 | 224 | |||
121 | 225 | return nil | ||
122 | 226 | |||
123 | 227 | } | ||
124 | 228 | |||
125 | 229 | // Unmount unmounts the image. This also unmaps the loop device. | ||
126 | 230 | func (img *BaseImage) Unmount() error { | ||
127 | 231 | if img.baseMount == "" { | ||
128 | 232 | panic("No base mountpoint set") | ||
129 | 233 | } | ||
130 | 234 | |||
131 | 235 | syscallSync() | ||
132 | 236 | |||
133 | 237 | for _, part := range img.parts { | ||
134 | 238 | if part.fs == fsNone { | ||
135 | 239 | continue | ||
136 | 240 | } | ||
137 | 241 | |||
138 | 242 | mountpoint := filepath.Join(img.baseMount, string(part.dir)) | ||
139 | 243 | if out, err := exec.Command("umount", mountpoint).CombinedOutput(); err != nil { | ||
140 | 244 | lsof, _ := exec.Command("lsof", "-w", mountpoint).CombinedOutput() | ||
141 | 245 | printOut(string(lsof)) | ||
142 | 246 | dev := filepath.Join("/dev/mapper", part.loop) | ||
143 | 247 | return ErrMount{dev: dev, mountpoint: mountpoint, fs: part.fs, out: out} | ||
144 | 248 | } | ||
145 | 249 | } | ||
146 | 250 | |||
147 | 251 | if err := os.RemoveAll(img.baseMount); err != nil { | ||
148 | 252 | return err | ||
149 | 253 | } | ||
150 | 254 | img.baseMount = "" | ||
151 | 255 | |||
152 | 256 | return img.Unmap() | ||
153 | 257 | } | ||
154 | 258 | |||
155 | 259 | // Map maps the image to loop devices | ||
156 | 260 | func (img *BaseImage) Map() error { | ||
157 | 261 | if isMapped(img.parts) { | ||
158 | 262 | panic("cannot double map partitions") | ||
159 | 263 | } | ||
160 | 264 | |||
161 | 265 | kpartxCmd := exec.Command("kpartx", "-avs", img.location) | ||
162 | 266 | stdout, err := kpartxCmd.StdoutPipe() | ||
163 | 267 | if err != nil { | ||
164 | 268 | return err | ||
165 | 269 | } | ||
166 | 270 | |||
167 | 271 | if err := kpartxCmd.Start(); err != nil { | ||
168 | 272 | return err | ||
169 | 273 | } | ||
170 | 274 | |||
171 | 275 | loops := make([]string, 0, img.partCount) | ||
172 | 276 | scanner := bufio.NewScanner(stdout) | ||
173 | 277 | for scanner.Scan() { | ||
174 | 278 | fields := strings.Fields(scanner.Text()) | ||
175 | 279 | |||
176 | 280 | if len(fields) > 2 { | ||
177 | 281 | loops = append(loops, fields[2]) | ||
178 | 282 | } else { | ||
179 | 283 | return fmt.Errorf("issues while determining drive mappings (%q)", fields) | ||
180 | 284 | } | ||
181 | 285 | } | ||
182 | 286 | if err := scanner.Err(); err != nil { | ||
183 | 287 | return err | ||
184 | 288 | } | ||
185 | 289 | |||
186 | 290 | if len(loops) != img.partCount { | ||
187 | 291 | return ErrMapCount{expectedParts: img.partCount, foundParts: len(loops)} | ||
188 | 292 | } | ||
189 | 293 | |||
190 | 294 | mapPartitions(img.parts, loops) | ||
191 | 295 | |||
192 | 296 | if err := kpartxCmd.Wait(); err != nil { | ||
193 | 297 | return err | ||
194 | 298 | } | ||
195 | 299 | |||
196 | 300 | return nil | ||
197 | 301 | } | ||
198 | 302 | |||
199 | 303 | //Unmap destroys loop devices for the partitions | ||
200 | 304 | func (img *BaseImage) Unmap() error { | ||
201 | 305 | if img.baseMount != "" { | ||
202 | 306 | panic("cannot unmap mounted partitions") | ||
203 | 307 | } | ||
204 | 308 | |||
205 | 309 | for _, part := range img.parts { | ||
206 | 310 | if err := exec.Command("dmsetup", "clear", part.loop).Run(); err != nil { | ||
207 | 311 | return err | ||
208 | 312 | } | ||
209 | 313 | } | ||
210 | 314 | |||
211 | 315 | if err := exec.Command("kpartx", "-ds", img.location).Run(); err != nil { | ||
212 | 316 | return err | ||
213 | 317 | } | ||
214 | 318 | |||
215 | 319 | unmapPartitions(img.parts) | ||
216 | 320 | |||
217 | 321 | return nil | ||
218 | 322 | } | ||
219 | 323 | |||
220 | 324 | // Format formats the image following the partition types and labels them | ||
221 | 325 | // accordingly. | ||
222 | 326 | func (img BaseImage) Format() error { | ||
223 | 327 | for _, part := range img.parts { | ||
224 | 328 | dev := filepath.Join("/dev/mapper", part.loop) | ||
225 | 329 | |||
226 | 330 | if part.fs == fsFat32 { | ||
227 | 331 | cmd := []string{"-F", "32", "-n", string(part.label)} | ||
228 | 332 | |||
229 | 333 | size, err := sectorSize(dev) | ||
230 | 334 | if err != nil { | ||
231 | 335 | return err | ||
232 | 336 | } | ||
233 | 337 | |||
234 | 338 | if size != "512" { | ||
235 | 339 | cmd = append(cmd, "-s", "1") | ||
236 | 340 | } | ||
237 | 341 | |||
238 | 342 | cmd = append(cmd, "-S", size, dev) | ||
239 | 343 | |||
240 | 344 | if out, err := exec.Command("mkfs.vfat", cmd...).CombinedOutput(); err != nil { | ||
241 | 345 | return fmt.Errorf("unable to create filesystem: %s", out) | ||
242 | 346 | } | ||
243 | 347 | } else { | ||
244 | 348 | if out, err := exec.Command("mkfs.ext4", "-F", "-L", string(part.label), dev).CombinedOutput(); err != nil { | ||
245 | 349 | return fmt.Errorf("unable to create filesystem: %s", out) | ||
246 | 350 | } | ||
247 | 351 | } | ||
248 | 352 | } | ||
249 | 353 | |||
250 | 354 | return nil | ||
251 | 355 | } | ||
252 | 356 | |||
253 | 357 | // User returns the writable path | ||
254 | 358 | func (img BaseImage) Writable() string { | ||
255 | 359 | if img.parts == nil { | ||
256 | 360 | panic("img is not setup with partitions") | ||
257 | 361 | } | ||
258 | 362 | |||
259 | 363 | if img.baseMount == "" { | ||
260 | 364 | panic("img not mounted") | ||
261 | 365 | } | ||
262 | 366 | |||
263 | 367 | return filepath.Join(img.baseMount, string(writableDir)) | ||
264 | 368 | } | ||
265 | 369 | |||
266 | 370 | func (img BaseImage) pathToMount(dir directory) string { | ||
267 | 371 | if img.parts == nil { | ||
268 | 372 | panic("img is not setup with partitions") | ||
269 | 373 | } | ||
270 | 374 | |||
271 | 375 | if img.baseMount == "" { | ||
272 | 376 | panic("img not mounted") | ||
273 | 377 | } | ||
274 | 378 | |||
275 | 379 | return filepath.Join(img.baseMount, string(dir)) | ||
276 | 380 | } | ||
277 | 381 | |||
278 | 382 | //System returns the system path | ||
279 | 383 | func (img BaseImage) System() string { | ||
280 | 384 | return img.pathToMount(systemADir) | ||
281 | 385 | } | ||
282 | 386 | |||
283 | 387 | // Boot returns the system-boot path | ||
284 | 388 | func (img BaseImage) Boot() string { | ||
285 | 389 | return img.pathToMount(bootDir) | ||
286 | 390 | } | ||
287 | 391 | |||
288 | 392 | // BaseMount returns the base directory used to mount the image partitions. | ||
289 | 393 | func (img BaseImage) BaseMount() string { | ||
290 | 394 | if img.baseMount == "" { | ||
291 | 395 | panic("image needs to be mounted") | ||
292 | 396 | } | ||
293 | 397 | |||
294 | 398 | return img.baseMount | ||
295 | 186 | } | 399 | } |
296 | 187 | 400 | ||
297 | 188 | func printOut(args ...interface{}) { | 401 | func printOut(args ...interface{}) { |
298 | 189 | 402 | ||
299 | === modified file 'diskimage/core_grub.go' | |||
300 | --- diskimage/core_grub.go 2015-06-11 03:13:19 +0000 | |||
301 | +++ diskimage/core_grub.go 2015-06-15 15:32:50 +0000 | |||
302 | @@ -8,14 +8,12 @@ | |||
303 | 8 | package diskimage | 8 | package diskimage |
304 | 9 | 9 | ||
305 | 10 | import ( | 10 | import ( |
306 | 11 | "bufio" | ||
307 | 12 | "errors" | 11 | "errors" |
308 | 13 | "fmt" | 12 | "fmt" |
309 | 14 | "io" | 13 | "io" |
310 | 15 | "os" | 14 | "os" |
311 | 16 | "os/exec" | 15 | "os/exec" |
312 | 17 | "path/filepath" | 16 | "path/filepath" |
313 | 18 | "strings" | ||
314 | 19 | "time" | 17 | "time" |
315 | 20 | 18 | ||
316 | 21 | "launchpad.net/goget-ubuntu-touch/sysutils" | 19 | "launchpad.net/goget-ubuntu-touch/sysutils" |
317 | @@ -34,21 +32,18 @@ | |||
318 | 34 | // with this program. If not, see <http://www.gnu.org/licenses/>. | 32 | // with this program. If not, see <http://www.gnu.org/licenses/>. |
319 | 35 | 33 | ||
320 | 36 | type CoreGrubImage struct { | 34 | type CoreGrubImage struct { |
328 | 37 | CoreImage | 35 | BaseImage |
322 | 38 | hardware HardwareDescription | ||
323 | 39 | oem OemDescription | ||
324 | 40 | location string | ||
325 | 41 | size int64 | ||
326 | 42 | baseMount string | ||
327 | 43 | parts []partition | ||
329 | 44 | } | 36 | } |
330 | 45 | 37 | ||
331 | 46 | func NewCoreGrubImage(location string, size int64, hw HardwareDescription, oem OemDescription) *CoreGrubImage { | 38 | func NewCoreGrubImage(location string, size int64, hw HardwareDescription, oem OemDescription) *CoreGrubImage { |
332 | 47 | return &CoreGrubImage{ | 39 | return &CoreGrubImage{ |
337 | 48 | location: location, | 40 | BaseImage{ |
338 | 49 | size: size, | 41 | location: location, |
339 | 50 | hardware: hw, | 42 | size: size, |
340 | 51 | oem: oem, | 43 | hardware: hw, |
341 | 44 | oem: oem, | ||
342 | 45 | partCount: 5, | ||
343 | 46 | }, | ||
344 | 52 | } | 47 | } |
345 | 53 | } | 48 | } |
346 | 54 | 49 | ||
347 | @@ -63,43 +58,6 @@ | |||
348 | 63 | configfile $prefix/grub.cfg | 58 | configfile $prefix/grub.cfg |
349 | 64 | ` | 59 | ` |
350 | 65 | 60 | ||
351 | 66 | func (img *CoreGrubImage) Mount() error { | ||
352 | 67 | baseMount, err := mount(img.parts) | ||
353 | 68 | if err != nil { | ||
354 | 69 | return err | ||
355 | 70 | } | ||
356 | 71 | img.baseMount = baseMount | ||
357 | 72 | |||
358 | 73 | return nil | ||
359 | 74 | } | ||
360 | 75 | |||
361 | 76 | func (img *CoreGrubImage) Unmount() (err error) { | ||
362 | 77 | if img.baseMount == "" { | ||
363 | 78 | panic("No base mountpoint set") | ||
364 | 79 | } | ||
365 | 80 | defer os.Remove(img.baseMount) | ||
366 | 81 | |||
367 | 82 | if out, err := exec.Command("sync").CombinedOutput(); err != nil { | ||
368 | 83 | return fmt.Errorf("Failed to sync filesystems before unmounting: %s", out) | ||
369 | 84 | } | ||
370 | 85 | |||
371 | 86 | for _, part := range img.parts { | ||
372 | 87 | if part.fs == fsNone { | ||
373 | 88 | continue | ||
374 | 89 | } | ||
375 | 90 | |||
376 | 91 | mountpoint := filepath.Join(img.baseMount, string(part.dir)) | ||
377 | 92 | if out, err := exec.Command("umount", "-l", mountpoint).CombinedOutput(); err != nil { | ||
378 | 93 | return fmt.Errorf("unable to unmount dir for image: %s", out) | ||
379 | 94 | } else { | ||
380 | 95 | } | ||
381 | 96 | } | ||
382 | 97 | |||
383 | 98 | img.baseMount = "" | ||
384 | 99 | |||
385 | 100 | return nil | ||
386 | 101 | } | ||
387 | 102 | |||
388 | 103 | //Partition creates a partitioned image from an img | 61 | //Partition creates a partitioned image from an img |
389 | 104 | func (img *CoreGrubImage) Partition() error { | 62 | func (img *CoreGrubImage) Partition() error { |
390 | 105 | if err := sysutils.CreateEmptyFile(img.location, img.size, sysutils.GB); err != nil { | 63 | if err := sysutils.CreateEmptyFile(img.location, img.size, sysutils.GB); err != nil { |
391 | @@ -125,150 +83,6 @@ | |||
392 | 125 | return parted.create(img.location) | 83 | return parted.create(img.location) |
393 | 126 | } | 84 | } |
394 | 127 | 85 | ||
395 | 128 | //Map creates loop devices for the partitions | ||
396 | 129 | func (img *CoreGrubImage) Map() error { | ||
397 | 130 | if isMapped(img.parts) { | ||
398 | 131 | panic("cannot double map partitions") | ||
399 | 132 | } | ||
400 | 133 | |||
401 | 134 | kpartxCmd := exec.Command("kpartx", "-avs", img.location) | ||
402 | 135 | stdout, err := kpartxCmd.StdoutPipe() | ||
403 | 136 | if err != nil { | ||
404 | 137 | return err | ||
405 | 138 | } | ||
406 | 139 | |||
407 | 140 | if err := kpartxCmd.Start(); err != nil { | ||
408 | 141 | return err | ||
409 | 142 | } | ||
410 | 143 | |||
411 | 144 | loops := make([]string, 0, 4) | ||
412 | 145 | scanner := bufio.NewScanner(stdout) | ||
413 | 146 | for scanner.Scan() { | ||
414 | 147 | fields := strings.Fields(scanner.Text()) | ||
415 | 148 | |||
416 | 149 | if len(fields) > 2 { | ||
417 | 150 | loops = append(loops, fields[2]) | ||
418 | 151 | } else { | ||
419 | 152 | return errors.New("issues while determining drive mappings") | ||
420 | 153 | } | ||
421 | 154 | } | ||
422 | 155 | if err := scanner.Err(); err != nil { | ||
423 | 156 | return err | ||
424 | 157 | } | ||
425 | 158 | |||
426 | 159 | // there are 5 partitions, so there should be five loop mounts | ||
427 | 160 | if len(loops) != 5 { | ||
428 | 161 | return errors.New("more partitions then expected while creating loop mapping") | ||
429 | 162 | } | ||
430 | 163 | |||
431 | 164 | mapPartitions(img.parts, loops) | ||
432 | 165 | |||
433 | 166 | if err := kpartxCmd.Wait(); err != nil { | ||
434 | 167 | return err | ||
435 | 168 | } | ||
436 | 169 | |||
437 | 170 | return nil | ||
438 | 171 | } | ||
439 | 172 | |||
440 | 173 | //Unmap destroys loop devices for the partitions | ||
441 | 174 | func (img *CoreGrubImage) Unmap() error { | ||
442 | 175 | if img.baseMount != "" { | ||
443 | 176 | panic("cannot unmap mounted partitions") | ||
444 | 177 | } | ||
445 | 178 | |||
446 | 179 | for _, part := range img.parts { | ||
447 | 180 | if err := exec.Command("dmsetup", "clear", part.loop).Run(); err != nil { | ||
448 | 181 | return err | ||
449 | 182 | } | ||
450 | 183 | } | ||
451 | 184 | |||
452 | 185 | if err := exec.Command("kpartx", "-d", img.location).Run(); err != nil { | ||
453 | 186 | return err | ||
454 | 187 | } | ||
455 | 188 | |||
456 | 189 | unmapPartitions(img.parts) | ||
457 | 190 | |||
458 | 191 | return nil | ||
459 | 192 | } | ||
460 | 193 | |||
461 | 194 | func (img CoreGrubImage) Format() error { | ||
462 | 195 | for _, part := range img.parts { | ||
463 | 196 | dev := filepath.Join("/dev/mapper", part.loop) | ||
464 | 197 | |||
465 | 198 | if part.fs == fsFat32 { | ||
466 | 199 | cmd := []string{"-F", "32", "-n", string(part.label)} | ||
467 | 200 | |||
468 | 201 | size, err := sectorSize(dev) | ||
469 | 202 | if err != nil { | ||
470 | 203 | return err | ||
471 | 204 | } | ||
472 | 205 | |||
473 | 206 | if size != "512" { | ||
474 | 207 | cmd = append(cmd, "-s", "1") | ||
475 | 208 | } | ||
476 | 209 | |||
477 | 210 | cmd = append(cmd, "-S", size, dev) | ||
478 | 211 | |||
479 | 212 | if out, err := exec.Command("mkfs.vfat", cmd...).CombinedOutput(); err != nil { | ||
480 | 213 | return fmt.Errorf("unable to create filesystem: %s", out) | ||
481 | 214 | } | ||
482 | 215 | } else if part.fs == fsExt4 { | ||
483 | 216 | if out, err := exec.Command("mkfs.ext4", "-F", "-L", string(part.label), dev).CombinedOutput(); err != nil { | ||
484 | 217 | return fmt.Errorf("unable to create filesystem: %s", out) | ||
485 | 218 | } | ||
486 | 219 | } | ||
487 | 220 | } | ||
488 | 221 | |||
489 | 222 | return nil | ||
490 | 223 | } | ||
491 | 224 | |||
492 | 225 | // User returns the writable path | ||
493 | 226 | func (img CoreGrubImage) Writable() string { | ||
494 | 227 | if img.parts == nil { | ||
495 | 228 | panic("img is not setup with partitions") | ||
496 | 229 | } | ||
497 | 230 | |||
498 | 231 | if img.baseMount == "" { | ||
499 | 232 | panic("img not mounted") | ||
500 | 233 | } | ||
501 | 234 | |||
502 | 235 | return filepath.Join(img.baseMount, string(writableDir)) | ||
503 | 236 | } | ||
504 | 237 | |||
505 | 238 | // Boot returns the system-boot path | ||
506 | 239 | func (img CoreGrubImage) Boot() string { | ||
507 | 240 | if img.parts == nil { | ||
508 | 241 | panic("img is not setup with partitions") | ||
509 | 242 | } | ||
510 | 243 | |||
511 | 244 | if img.baseMount == "" { | ||
512 | 245 | panic("img not mounted") | ||
513 | 246 | } | ||
514 | 247 | |||
515 | 248 | return filepath.Join(img.baseMount, string(bootDir)) | ||
516 | 249 | } | ||
517 | 250 | |||
518 | 251 | //System returns the system path | ||
519 | 252 | func (img CoreGrubImage) System() string { | ||
520 | 253 | if img.parts == nil { | ||
521 | 254 | panic("img is not setup with partitions") | ||
522 | 255 | } | ||
523 | 256 | |||
524 | 257 | if img.baseMount == "" { | ||
525 | 258 | panic("img not mounted") | ||
526 | 259 | } | ||
527 | 260 | |||
528 | 261 | return filepath.Join(img.baseMount, string(systemADir)) | ||
529 | 262 | } | ||
530 | 263 | |||
531 | 264 | func (img CoreGrubImage) BaseMount() string { | ||
532 | 265 | if img.baseMount == "" { | ||
533 | 266 | panic("image needs to be mounted") | ||
534 | 267 | } | ||
535 | 268 | |||
536 | 269 | return img.baseMount | ||
537 | 270 | } | ||
538 | 271 | |||
539 | 272 | func (img *CoreGrubImage) SetupBoot(oemRootPath string) error { | 86 | func (img *CoreGrubImage) SetupBoot(oemRootPath string) error { |
540 | 273 | for _, dev := range []string{"dev", "proc", "sys"} { | 87 | for _, dev := range []string{"dev", "proc", "sys"} { |
541 | 274 | src := filepath.Join("/", dev) | 88 | src := filepath.Join("/", dev) |
542 | 275 | 89 | ||
543 | === modified file 'diskimage/core_uboot.go' | |||
544 | --- diskimage/core_uboot.go 2015-06-11 03:13:19 +0000 | |||
545 | +++ diskimage/core_uboot.go 2015-06-15 15:32:50 +0000 | |||
546 | @@ -8,14 +8,10 @@ | |||
547 | 8 | package diskimage | 8 | package diskimage |
548 | 9 | 9 | ||
549 | 10 | import ( | 10 | import ( |
550 | 11 | "bufio" | ||
551 | 12 | "errors" | ||
552 | 13 | "fmt" | 11 | "fmt" |
553 | 14 | "io/ioutil" | 12 | "io/ioutil" |
554 | 15 | "os" | 13 | "os" |
555 | 16 | "os/exec" | ||
556 | 17 | "path/filepath" | 14 | "path/filepath" |
557 | 18 | "strings" | ||
558 | 19 | "text/template" | 15 | "text/template" |
559 | 20 | 16 | ||
560 | 21 | "launchpad.net/goget-ubuntu-touch/sysutils" | 17 | "launchpad.net/goget-ubuntu-touch/sysutils" |
561 | @@ -34,14 +30,7 @@ | |||
562 | 34 | // with this program. If not, see <http://www.gnu.org/licenses/>. | 30 | // with this program. If not, see <http://www.gnu.org/licenses/>. |
563 | 35 | 31 | ||
564 | 36 | type CoreUBootImage struct { | 32 | type CoreUBootImage struct { |
573 | 37 | CoreImage | 33 | BaseImage |
566 | 38 | SystemImage | ||
567 | 39 | hardware HardwareDescription | ||
568 | 40 | oem OemDescription | ||
569 | 41 | location string | ||
570 | 42 | size int64 | ||
571 | 43 | baseMount string | ||
572 | 44 | parts []partition | ||
574 | 45 | } | 34 | } |
575 | 46 | 35 | ||
576 | 47 | const snappySystemTemplate = `# This is a snappy variables and boot logic file and is entirely generated and | 36 | const snappySystemTemplate = `# This is a snappy variables and boot logic file and is entirely generated and |
577 | @@ -79,44 +68,14 @@ | |||
578 | 79 | 68 | ||
579 | 80 | func NewCoreUBootImage(location string, size int64, hw HardwareDescription, oem OemDescription) *CoreUBootImage { | 69 | func NewCoreUBootImage(location string, size int64, hw HardwareDescription, oem OemDescription) *CoreUBootImage { |
580 | 81 | return &CoreUBootImage{ | 70 | return &CoreUBootImage{ |
619 | 82 | hardware: hw, | 71 | BaseImage{ |
620 | 83 | oem: oem, | 72 | hardware: hw, |
621 | 84 | location: location, | 73 | oem: oem, |
622 | 85 | size: size, | 74 | location: location, |
623 | 86 | } | 75 | size: size, |
624 | 87 | } | 76 | partCount: 4, |
625 | 88 | 77 | }, | |
626 | 89 | func (img *CoreUBootImage) Mount() error { | 78 | } |
589 | 90 | baseMount, err := mount(img.parts) | ||
590 | 91 | if err != nil { | ||
591 | 92 | return err | ||
592 | 93 | } | ||
593 | 94 | img.baseMount = baseMount | ||
594 | 95 | |||
595 | 96 | return nil | ||
596 | 97 | } | ||
597 | 98 | |||
598 | 99 | func (img *CoreUBootImage) Unmount() (err error) { | ||
599 | 100 | if img.baseMount == "" { | ||
600 | 101 | panic("No base mountpoint set") | ||
601 | 102 | } | ||
602 | 103 | defer func() { | ||
603 | 104 | os.Remove(img.baseMount) | ||
604 | 105 | img.baseMount = "" | ||
605 | 106 | }() | ||
606 | 107 | |||
607 | 108 | if out, err := exec.Command("sync").CombinedOutput(); err != nil { | ||
608 | 109 | return fmt.Errorf("Failed to sync filesystems before unmounting: %s", out) | ||
609 | 110 | } | ||
610 | 111 | |||
611 | 112 | for _, part := range img.parts { | ||
612 | 113 | mountpoint := filepath.Join(img.baseMount, string(part.dir)) | ||
613 | 114 | if out, err := exec.Command("umount", "-l", mountpoint).CombinedOutput(); err != nil { | ||
614 | 115 | panic(fmt.Sprintf("unable to unmount dir for image: %s", out)) | ||
615 | 116 | } | ||
616 | 117 | } | ||
617 | 118 | |||
618 | 119 | return nil | ||
627 | 120 | } | 79 | } |
628 | 121 | 80 | ||
629 | 122 | //Partition creates a partitioned image from an img | 81 | //Partition creates a partitioned image from an img |
630 | @@ -142,137 +101,6 @@ | |||
631 | 142 | return parted.create(img.location) | 101 | return parted.create(img.location) |
632 | 143 | } | 102 | } |
633 | 144 | 103 | ||
634 | 145 | //Map creates loop devices for the partitions | ||
635 | 146 | func (img *CoreUBootImage) Map() error { | ||
636 | 147 | if isMapped(img.parts) { | ||
637 | 148 | panic("cannot double map partitions") | ||
638 | 149 | } | ||
639 | 150 | |||
640 | 151 | kpartxCmd := exec.Command("kpartx", "-avs", img.location) | ||
641 | 152 | stdout, err := kpartxCmd.StdoutPipe() | ||
642 | 153 | if err != nil { | ||
643 | 154 | return err | ||
644 | 155 | } | ||
645 | 156 | |||
646 | 157 | if err := kpartxCmd.Start(); err != nil { | ||
647 | 158 | return err | ||
648 | 159 | } | ||
649 | 160 | |||
650 | 161 | loops := make([]string, 0, 4) | ||
651 | 162 | scanner := bufio.NewScanner(stdout) | ||
652 | 163 | for scanner.Scan() { | ||
653 | 164 | fields := strings.Fields(scanner.Text()) | ||
654 | 165 | |||
655 | 166 | if len(fields) > 2 { | ||
656 | 167 | loops = append(loops, fields[2]) | ||
657 | 168 | } else { | ||
658 | 169 | return errors.New("issues while determining drive mappings") | ||
659 | 170 | } | ||
660 | 171 | } | ||
661 | 172 | if err := scanner.Err(); err != nil { | ||
662 | 173 | return err | ||
663 | 174 | } | ||
664 | 175 | |||
665 | 176 | // there are 5 partitions, so there should be five loop mounts | ||
666 | 177 | if len(loops) != 4 { | ||
667 | 178 | return errors.New("more partitions then expected while creating loop mapping") | ||
668 | 179 | } | ||
669 | 180 | |||
670 | 181 | mapPartitions(img.parts, loops) | ||
671 | 182 | |||
672 | 183 | if err := kpartxCmd.Wait(); err != nil { | ||
673 | 184 | return err | ||
674 | 185 | } | ||
675 | 186 | |||
676 | 187 | return nil | ||
677 | 188 | } | ||
678 | 189 | |||
679 | 190 | //Unmap destroys loop devices for the partitions | ||
680 | 191 | func (img *CoreUBootImage) Unmap() error { | ||
681 | 192 | if img.baseMount != "" { | ||
682 | 193 | panic("cannot unmap mounted partitions") | ||
683 | 194 | } | ||
684 | 195 | |||
685 | 196 | for _, part := range img.parts { | ||
686 | 197 | if err := exec.Command("dmsetup", "clear", part.loop).Run(); err != nil { | ||
687 | 198 | return err | ||
688 | 199 | } | ||
689 | 200 | } | ||
690 | 201 | |||
691 | 202 | if err := exec.Command("kpartx", "-d", img.location).Run(); err != nil { | ||
692 | 203 | return err | ||
693 | 204 | } | ||
694 | 205 | |||
695 | 206 | unmapPartitions(img.parts) | ||
696 | 207 | |||
697 | 208 | return nil | ||
698 | 209 | } | ||
699 | 210 | |||
700 | 211 | func (img CoreUBootImage) Format() error { | ||
701 | 212 | for _, part := range img.parts { | ||
702 | 213 | dev := filepath.Join("/dev/mapper", part.loop) | ||
703 | 214 | |||
704 | 215 | if part.fs == fsFat32 { | ||
705 | 216 | cmd := []string{"-F", "32", "-n", string(part.label)} | ||
706 | 217 | |||
707 | 218 | size, err := sectorSize(dev) | ||
708 | 219 | if err != nil { | ||
709 | 220 | return err | ||
710 | 221 | } | ||
711 | 222 | |||
712 | 223 | if size != "512" { | ||
713 | 224 | cmd = append(cmd, "-s", "1") | ||
714 | 225 | } | ||
715 | 226 | |||
716 | 227 | cmd = append(cmd, "-S", size, dev) | ||
717 | 228 | |||
718 | 229 | if out, err := exec.Command("mkfs.vfat", cmd...).CombinedOutput(); err != nil { | ||
719 | 230 | return fmt.Errorf("unable to create filesystem: %s", out) | ||
720 | 231 | } | ||
721 | 232 | } else { | ||
722 | 233 | if out, err := exec.Command("mkfs.ext4", "-F", "-L", string(part.label), dev).CombinedOutput(); err != nil { | ||
723 | 234 | return fmt.Errorf("unable to create filesystem: %s", out) | ||
724 | 235 | } | ||
725 | 236 | } | ||
726 | 237 | } | ||
727 | 238 | |||
728 | 239 | return nil | ||
729 | 240 | } | ||
730 | 241 | |||
731 | 242 | // User returns the writable path | ||
732 | 243 | func (img *CoreUBootImage) Writable() string { | ||
733 | 244 | if img.parts == nil { | ||
734 | 245 | panic("img is not setup with partitions") | ||
735 | 246 | } | ||
736 | 247 | |||
737 | 248 | if img.baseMount == "" { | ||
738 | 249 | panic("img not mounted") | ||
739 | 250 | } | ||
740 | 251 | |||
741 | 252 | return filepath.Join(img.baseMount, string(writableDir)) | ||
742 | 253 | } | ||
743 | 254 | |||
744 | 255 | //System returns the system path | ||
745 | 256 | func (img *CoreUBootImage) System() string { | ||
746 | 257 | if img.parts == nil { | ||
747 | 258 | panic("img is not setup with partitions") | ||
748 | 259 | } | ||
749 | 260 | |||
750 | 261 | if img.baseMount == "" { | ||
751 | 262 | panic("img not mounted") | ||
752 | 263 | } | ||
753 | 264 | |||
754 | 265 | return filepath.Join(img.baseMount, string(systemADir)) | ||
755 | 266 | } | ||
756 | 267 | |||
757 | 268 | func (img CoreUBootImage) BaseMount() string { | ||
758 | 269 | if img.baseMount == "" { | ||
759 | 270 | panic("image needs to be mounted") | ||
760 | 271 | } | ||
761 | 272 | |||
762 | 273 | return img.baseMount | ||
763 | 274 | } | ||
764 | 275 | |||
765 | 276 | func (img CoreUBootImage) SetupBoot(oemRootPath string) error { | 104 | func (img CoreUBootImage) SetupBoot(oemRootPath string) error { |
766 | 277 | // destinations | 105 | // destinations |
767 | 278 | bootPath := filepath.Join(img.baseMount, string(bootDir)) | 106 | bootPath := filepath.Join(img.baseMount, string(bootDir)) |
768 | 279 | 107 | ||
769 | === added file 'diskimage/errors.go' | |||
770 | --- diskimage/errors.go 1970-01-01 00:00:00 +0000 | |||
771 | +++ diskimage/errors.go 2015-06-15 15:32:50 +0000 | |||
772 | @@ -0,0 +1,32 @@ | |||
773 | 1 | // | ||
774 | 2 | // diskimage - handles ubuntu disk images | ||
775 | 3 | // | ||
776 | 4 | // Copyright (c) 2015 Canonical Ltd. | ||
777 | 5 | // | ||
778 | 6 | // Written by Sergio Schvezov <sergio.schvezov@canonical.com> | ||
779 | 7 | // | ||
780 | 8 | package diskimage | ||
781 | 9 | |||
782 | 10 | import "fmt" | ||
783 | 11 | |||
784 | 12 | // ErrMount represents a mount error | ||
785 | 13 | type ErrMount struct { | ||
786 | 14 | dev string | ||
787 | 15 | mountpoint string | ||
788 | 16 | fs fsType | ||
789 | 17 | out []byte | ||
790 | 18 | } | ||
791 | 19 | |||
792 | 20 | func (e ErrMount) Error() string { | ||
793 | 21 | return fmt.Sprintf("cannot mount %s(%s) on %s: %s", e.dev, e.fs, e.mountpoint, e.out) | ||
794 | 22 | } | ||
795 | 23 | |||
796 | 24 | // ErrMapCount represents an error on the expected amount of partitions | ||
797 | 25 | type ErrMapCount struct { | ||
798 | 26 | foundParts int | ||
799 | 27 | expectedParts int | ||
800 | 28 | } | ||
801 | 29 | |||
802 | 30 | func (e ErrMapCount) Error() string { | ||
803 | 31 | return fmt.Sprintf("expected %d partitons but found %d", e.expectedParts, e.foundParts) | ||
804 | 32 | } | ||
805 | 0 | 33 | ||
806 | === modified file 'ubuntu-device-flash/core.go' | |||
807 | --- ubuntu-device-flash/core.go 2015-06-09 13:57:34 +0000 | |||
808 | +++ ubuntu-device-flash/core.go 2015-06-15 15:32:50 +0000 | |||
809 | @@ -322,24 +322,14 @@ | |||
810 | 322 | } | 322 | } |
811 | 323 | 323 | ||
812 | 324 | func (coreCmd *CoreCmd) setup(img diskimage.CoreImage, filePathChan <-chan string, fileCount int) error { | 324 | func (coreCmd *CoreCmd) setup(img diskimage.CoreImage, filePathChan <-chan string, fileCount int) error { |
813 | 325 | printOut("Mapping...") | ||
814 | 326 | if err := img.Map(); err != nil { | ||
815 | 327 | return err | ||
816 | 328 | } | ||
817 | 329 | defer func() { | ||
818 | 330 | printOut("Unmapping...") | ||
819 | 331 | defer img.Unmap() | ||
820 | 332 | }() | ||
821 | 333 | |||
822 | 334 | printOut("Mounting...") | 325 | printOut("Mounting...") |
823 | 335 | if err := img.Mount(); err != nil { | 326 | if err := img.Mount(); err != nil { |
824 | 336 | fmt.Println(err) | ||
825 | 337 | return err | 327 | return err |
826 | 338 | } | 328 | } |
827 | 339 | defer func() { | 329 | defer func() { |
828 | 340 | printOut("Unmounting...") | 330 | printOut("Unmounting...") |
829 | 341 | if err := img.Unmount(); err != nil { | 331 | if err := img.Unmount(); err != nil { |
831 | 342 | fmt.Println(err) | 332 | fmt.Println("WARNING: unexpected issue:", err) |
832 | 343 | } | 333 | } |
833 | 344 | }() | 334 | }() |
834 | 345 | 335 |
Woah, very nice consolidation. I have a lot of questions in the begining probably because its very hot here. Feel free to ignore, this is great and fine to land - I like how it kills duplication.