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