Skip to content

Commit 62aedf1

Browse files
authored
feat: Cleanup directories created by simulator when it stops (#11)
1 parent e5c2515 commit 62aedf1

2 files changed

Lines changed: 145 additions & 62 deletions

File tree

pkg/simulator/filesystem.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package simulator
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
)
8+
9+
type FileSystemManager struct {
10+
instanceDir string
11+
firmwareDir string
12+
createdDirs []string
13+
}
14+
15+
func NewFileSystemManager(rootDir string, index uint) *FileSystemManager {
16+
instanceName := fmt.Sprintf("remoteproc%d", index)
17+
return &FileSystemManager{
18+
instanceDir: filepath.Join(rootDir, "sys", "class", "remoteproc", instanceName),
19+
firmwareDir: filepath.Join(rootDir, "lib", "firmware"),
20+
createdDirs: []string{},
21+
}
22+
}
23+
24+
func (fs *FileSystemManager) BootstrapDirectories() error {
25+
createdInstancePath, err := mkdirAll(fs.instanceDir, 0755)
26+
if err != nil {
27+
return fmt.Errorf("failed to create instance directory: %w", err)
28+
}
29+
if createdInstancePath != "" {
30+
fs.createdDirs = append(fs.createdDirs, createdInstancePath)
31+
}
32+
33+
createdFirmwarePath, err := mkdirAll(fs.firmwareDir, 0755)
34+
if err != nil {
35+
fs.Cleanup()
36+
return fmt.Errorf("failed to create firmware directory: %w", err)
37+
}
38+
if createdFirmwarePath != "" {
39+
fs.createdDirs = append(fs.createdDirs, createdFirmwarePath)
40+
}
41+
42+
return nil
43+
}
44+
45+
func (fs *FileSystemManager) WriteInstanceFile(filename, content string) error {
46+
path := filepath.Join(fs.instanceDir, filename)
47+
err := os.WriteFile(path, []byte(content), 0644)
48+
if err != nil {
49+
return fmt.Errorf("failed to write %s: %w", filename, err)
50+
}
51+
return nil
52+
}
53+
54+
func (fs *FileSystemManager) FirmwareExists(firmwareName string) bool {
55+
path := filepath.Join(fs.firmwareDir, firmwareName)
56+
_, err := os.Stat(path)
57+
return !os.IsNotExist(err)
58+
}
59+
60+
func (fs *FileSystemManager) InstanceDir() string {
61+
return fs.instanceDir
62+
}
63+
64+
func (fs *FileSystemManager) FirmwareDir() string {
65+
return fs.firmwareDir
66+
}
67+
68+
func (fs *FileSystemManager) Cleanup() error {
69+
for _, dir := range fs.createdDirs {
70+
if err := os.RemoveAll(dir); err != nil {
71+
return fmt.Errorf("failed to remove directory %s: %w", dir, err)
72+
}
73+
}
74+
fs.createdDirs = []string{}
75+
return nil
76+
}
77+
78+
func mkdirAll(path string, perm os.FileMode) (string, error) {
79+
current := path
80+
var topmostMissing string
81+
82+
for current != "/" && current != "." {
83+
_, err := os.Stat(current)
84+
dirExists := err == nil
85+
if dirExists {
86+
break
87+
}
88+
if !os.IsNotExist(err) {
89+
return "", err
90+
}
91+
topmostMissing = current
92+
current = filepath.Dir(current)
93+
}
94+
95+
if topmostMissing == "" {
96+
return "", nil
97+
}
98+
99+
if err := os.MkdirAll(path, perm); err != nil {
100+
return "", err
101+
}
102+
103+
return topmostMissing, nil
104+
}

pkg/simulator/remoteproc.go

Lines changed: 41 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,18 @@ import (
44
"errors"
55
"fmt"
66
"log"
7-
"os"
8-
"path/filepath"
97
"time"
108

119
"github.com/Arm-Debug/remoteproc-simulator/internal/dirwatcher"
1210
)
1311

1412
type Remoteproc struct {
15-
rootDir string
16-
index uint
17-
name string
18-
19-
instanceDir string
20-
firmwareDir string
21-
watcher *dirwatcher.DirWatcher
22-
state state
23-
firmware string
24-
stopChan chan struct{}
13+
name string
14+
fs *FileSystemManager
15+
watcher *dirwatcher.DirWatcher
16+
state state
17+
firmware string
18+
stopChan chan struct{}
2519
}
2620

2721
const (
@@ -59,74 +53,73 @@ func NewRemoteproc(config Config) (*Remoteproc, error) {
5953
}
6054

6155
r := &Remoteproc{
62-
rootDir: config.RootDir,
63-
index: config.Index,
6456
name: config.Name,
57+
fs: NewFileSystemManager(config.RootDir, config.Index),
6558
firmware: initialFirmware,
6659
state: initialState,
6760
}
6861

69-
instanceDirName := fmt.Sprintf("remoteproc%d", r.index)
70-
r.instanceDir = filepath.Join(r.rootDir, "sys", "class", "remoteproc", instanceDirName)
71-
r.firmwareDir = filepath.Join(r.rootDir, "lib", "firmware")
72-
73-
return r, r.start()
62+
err := r.start()
63+
if err != nil {
64+
r.Close()
65+
}
66+
return r, err
7467
}
7568

7669
func (r *Remoteproc) start() error {
77-
files := map[string]string{
78-
stateFileName: r.state.String(),
79-
firmwareFileName: r.firmware,
80-
nameFileName: r.name,
81-
}
82-
if err := r.bootstrapInstanceDir(files); err != nil {
83-
return fmt.Errorf("failed to bootstrap sysfs: %w", err)
70+
if err := r.bootstrapDirectoryStructure(); err != nil {
71+
return fmt.Errorf("failed to bootstrap directory structure: %w", err)
8472
}
8573

86-
if err := r.bootstrapFirmwareDir(); err != nil {
87-
return fmt.Errorf("failed to bootstrap firmware dir: %w", err)
88-
}
89-
90-
watcher, err := dirwatcher.New(r.instanceDir)
74+
watcher, err := dirwatcher.New(r.fs.InstanceDir())
9175
if err != nil {
9276
return fmt.Errorf("failed to setup directory watcher: %w", err)
9377
}
94-
9578
r.watcher = watcher
9679

9780
r.stopChan = make(chan struct{})
9881
go r.loop()
9982

100-
log.Printf("Remoteproc initialized at %s", r.instanceDir)
83+
log.Printf("Remoteproc initialized at %s", r.fs.InstanceDir())
10184
return nil
10285
}
10386

10487
func (r *Remoteproc) Close() error {
105-
var err error
88+
var watcherErr error
10689
if r.watcher != nil {
107-
err = r.watcher.Close()
90+
watcherErr = r.watcher.Close()
10891
}
92+
10993
if r.stopChan != nil {
11094
close(r.stopChan)
11195
}
112-
return err
96+
97+
var fsErr error
98+
if r.fs != nil {
99+
fsErr = r.fs.Cleanup()
100+
}
101+
102+
return errors.Join(watcherErr, fsErr)
113103
}
114104

115-
func (r *Remoteproc) bootstrapInstanceDir(files map[string]string) error {
116-
err := os.MkdirAll(r.instanceDir, 0755)
117-
if err != nil {
105+
func (r *Remoteproc) bootstrapDirectoryStructure() error {
106+
if err := r.fs.BootstrapDirectories(); err != nil {
118107
return err
119108
}
109+
110+
files := map[string]string{
111+
stateFileName: r.state.String(),
112+
firmwareFileName: r.firmware,
113+
nameFileName: r.name,
114+
}
115+
120116
for filename, content := range files {
121-
if err := r.writeFile(filename, content); err != nil {
117+
if err := r.fs.WriteInstanceFile(filename, content); err != nil {
122118
return err
123119
}
124120
}
125-
return nil
126-
}
127121

128-
func (r *Remoteproc) bootstrapFirmwareDir() error {
129-
return os.MkdirAll(r.firmwareDir, 0755)
122+
return nil
130123
}
131124

132125
func (r *Remoteproc) loop() {
@@ -170,8 +163,8 @@ func (r *Remoteproc) handleStateChange(value string) {
170163
return
171164
}
172165

173-
if !fileExists(filepath.Join(r.firmwareDir, r.firmware)) {
174-
log.Printf("Cannot start: firmware file not found in %s directory", r.firmwareDir)
166+
if !r.fs.FirmwareExists(r.firmware) {
167+
log.Printf("Cannot start: firmware file not found in %s directory", r.fs.FirmwareDir())
175168
r.setState(r.state)
176169
return
177170
}
@@ -205,37 +198,23 @@ func (r *Remoteproc) handleStateChange(value string) {
205198

206199
func (r *Remoteproc) setState(state state) {
207200
r.state = state
208-
r.writeFile(stateFileName, state.String())
201+
r.fs.WriteInstanceFile(stateFileName, state.String())
209202
}
210203

211204
func (r *Remoteproc) handleFirmwareChange(value string) {
212205
if r.state == StateRunning {
213206
log.Printf("Cannot change firmware while Remoteproc is %s", r.state)
214-
r.writeFile(firmwareFileName, r.firmware)
207+
r.fs.WriteInstanceFile(firmwareFileName, r.firmware)
215208
return
216209
}
217210
r.firmware = value
218211
log.Printf("Firmware set to %s", value)
219212
}
220213

221-
func (r *Remoteproc) writeFile(filename, content string) error {
222-
path := filepath.Join(r.instanceDir, filename)
223-
err := os.WriteFile(path, []byte(content), 0644)
224-
if err != nil {
225-
return fmt.Errorf("failed to write %s: %v", filename, err)
226-
}
227-
return nil
228-
}
229-
230214
func isStateSelfInflicted(value string) bool {
231215
switch value {
232216
case StateRunning.String(), StateCrashed.String(), StateOffline.String():
233217
return true
234218
}
235219
return false
236220
}
237-
238-
func fileExists(filename string) bool {
239-
_, err := os.Stat(filename)
240-
return !os.IsNotExist(err)
241-
}

0 commit comments

Comments
 (0)