-
Notifications
You must be signed in to change notification settings - Fork 19
/
prepareForCapture.go
131 lines (125 loc) · 3.76 KB
/
prepareForCapture.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
package unpacker
import (
"errors"
"fmt"
"os"
"path/filepath"
"syscall"
"time"
"github.com/Symantec/Dominator/lib/filesystem"
"github.com/Symantec/Dominator/lib/filesystem/util"
"github.com/Symantec/Dominator/lib/format"
proto "github.com/Symantec/Dominator/proto/imageunpacker"
)
func scanBootDirectory(rootDir string) (*filesystem.FileSystem, error) {
file, err := os.Open(filepath.Join(rootDir, "boot"))
if err != nil {
return nil, err
}
defer file.Close()
names, err := file.Readdirnames(-1)
if err != nil {
return nil, err
}
bootInode := &filesystem.DirectoryInode{}
for _, name := range names {
bootInode.EntryList = append(bootInode.EntryList,
&filesystem.DirectoryEntry{Name: name})
}
bootEntry := &filesystem.DirectoryEntry{Name: "boot"}
bootEntry.SetInode(bootInode)
fs := &filesystem.FileSystem{
DirectoryInode: filesystem.DirectoryInode{
EntryList: []*filesystem.DirectoryEntry{bootEntry},
},
}
return fs, nil
}
func (u *Unpacker) prepareForCapture(streamName string) error {
u.updateUsageTime()
defer u.updateUsageTime()
streamInfo := u.getStream(streamName)
if streamInfo == nil {
return errors.New("unknown stream")
}
errorChannel := make(chan error)
request := requestType{
request: requestPrepareForCapture,
errorChannel: errorChannel,
}
streamInfo.requestChannel <- request
return <-errorChannel
}
func (stream *streamManagerState) prepareForCapture() error {
if err := stream.getDevice(); err != nil {
return err
}
mountPoint := filepath.Join(stream.unpacker.baseDir, "mnt")
if err := stream.mount(mountPoint); err != nil {
return err
}
streamInfo := stream.streamInfo
switch streamInfo.status {
case proto.StatusStreamNoDevice:
return errors.New("no device")
case proto.StatusStreamNotMounted:
return errors.New("not mounted")
case proto.StatusStreamMounted:
// Start preparing.
case proto.StatusStreamScanning:
return errors.New("stream scan in progress")
case proto.StatusStreamScanned:
return errors.New("stream not idle")
case proto.StatusStreamFetching:
return errors.New("fetch in progress")
case proto.StatusStreamUpdating:
return errors.New("update in progress")
case proto.StatusStreamPreparing:
return errors.New("already preparing to capture")
default:
panic("invalid status")
}
streamInfo.status = proto.StatusStreamPreparing
startTime := time.Now()
err := stream.capture()
if err != nil {
stream.streamInfo.status = proto.StatusStreamMounted
return err
}
stream.streamInfo.status = proto.StatusStreamNotMounted
stream.unpacker.logger.Printf("Prepared for capture(%s) in %s\n",
stream.streamName, format.Duration(time.Since(startTime)))
return nil
}
func (stream *streamManagerState) capture() error {
stream.unpacker.rwMutex.RLock()
device := stream.unpacker.pState.Devices[stream.streamInfo.DeviceId]
stream.unpacker.rwMutex.RUnlock()
deviceNode := filepath.Join("/dev", device.DeviceName)
stream.unpacker.logger.Printf(
"Preparing for capture(%s) on %s with label: %s\n",
stream.streamName, deviceNode, stream.rootLabel)
// First clean out debris.
mountPoint := filepath.Join(stream.unpacker.baseDir, "mnt")
subdDir := filepath.Join(mountPoint, ".subd")
if err := os.RemoveAll(subdDir); err != nil {
return err
}
fs, err := scanBootDirectory(mountPoint)
if err != nil {
stream.unpacker.logger.Printf("Error scanning boot directory: %s\n",
err)
return fmt.Errorf("error getting scanning boot directory: %s", err)
}
err = util.MakeBootable(fs, deviceNode, stream.rootLabel, mountPoint,
"net.ifnames=0", false, stream.unpacker.logger)
if err != nil {
stream.unpacker.logger.Printf("Error preparing: %s", err)
return fmt.Errorf("error preparing: %s", err)
}
if err := syscall.Unmount(mountPoint, 0); err != nil {
return err
}
syscall.Sync()
return nil
}