-
Notifications
You must be signed in to change notification settings - Fork 136
/
raw_action.go
136 lines (112 loc) · 3.26 KB
/
raw_action.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
Raw Action
Directly write a file to the output image at a given offset.
This is typically useful for bootloaders.
Yaml syntax:
- action: raw
origin: name
source: filename
offset: bytes
Mandatory properties:
- origin -- reference to named file or directory.
- source -- the name of file located in 'origin' to be written into the output image.
Optional properties:
- offset -- offset in bytes for output image file.
It is possible to use internal templating mechanism of debos to calculate offset
with sectors (512 bytes) instead of bytes, for instance: '{{ sector 256 }}'.
The default value is zero.
- partition -- named partition to write to
*/
package actions
import (
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path"
"strconv"
"github.com/go-debos/debos"
)
type RawAction struct {
debos.BaseAction `yaml:",inline"`
Origin string // there the source comes from
Offset string
Source string // relative path inside of origin
Path string // deprecated option (for backward compatibility)
Partition string // Partition to write otherwise full image
}
func (raw *RawAction) checkDeprecatedSyntax() error {
// New syntax is based on 'origin' and 'source'
// Check if we do not mix new and old syntax
// TODO: remove deprecated syntax verification
if len(raw.Path) > 0 {
// Deprecated syntax based on 'source' and 'path'
log.Printf("Usage of 'source' and 'path' properties is deprecated.")
log.Printf("Please use 'origin' and 'source' properties.")
if len(raw.Origin) > 0 {
return errors.New("Can't mix 'origin' and 'path'(deprecated option) properties")
}
if len(raw.Source) == 0 {
return errors.New("'source' and 'path' properties can't be empty")
}
// Switch to new syntax
raw.Origin = raw.Source
raw.Source = raw.Path
raw.Path = ""
}
return nil
}
func (raw *RawAction) Verify(context *debos.DebosContext) error {
if err := raw.checkDeprecatedSyntax(); err != nil {
return err
}
if len(raw.Origin) == 0 || len(raw.Source) == 0 {
return errors.New("'origin' and 'source' properties can't be empty")
}
return nil
}
func (raw *RawAction) Run(context *debos.DebosContext) error {
raw.LogStart()
origin, found := context.Origins[raw.Origin]
if !found {
return fmt.Errorf("Origin `%s` doesn't exist\n", raw.Origin)
}
s := path.Join(origin, raw.Source)
content, err := ioutil.ReadFile(s)
if err != nil {
return fmt.Errorf("Failed to read %s", s)
}
var devicePath string
if raw.Partition != "" {
for _, p := range context.ImagePartitions {
if p.Name == raw.Partition {
devicePath = p.DevicePath
break
}
}
if devicePath == "" {
return fmt.Errorf("Failed to find partition named %s", raw.Partition)
}
} else {
devicePath = context.Image
}
target, err := os.OpenFile(devicePath, os.O_WRONLY, 0)
if err != nil {
return fmt.Errorf("Failed to open %s: %v", devicePath, err)
}
defer target.Close()
offset, err := strconv.ParseInt(raw.Offset, 0, 64)
if err != nil {
return fmt.Errorf("Couldn't parse offset %v", err)
}
bytes, err := target.WriteAt(content, offset)
if bytes != len(content) {
return fmt.Errorf("Couldn't write complete data %v", err)
}
err = target.Sync()
if err != nil {
return fmt.Errorf("Couldn't sync content %v", err)
}
return nil
}