Skip to content

Commit 3f8b30c

Browse files
committed
feat(usb_mass_storage): mount as disk
1 parent 77b4c1c commit 3f8b30c

File tree

4 files changed

+99
-21
lines changed

4 files changed

+99
-21
lines changed

internal/usbgadget/config.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,29 @@ func (u *UsbGadget) GetPath(itemKey string) (string, error) {
137137
return joinPath(u.kvmGadgetPath, item.path), nil
138138
}
139139

140+
// OverrideGadgetConfig overrides the gadget config for the given item and attribute.
141+
// It returns an error if the item is not found or the attribute is not found.
142+
// It returns true if the attribute is overridden, false otherwise.
143+
func (u *UsbGadget) OverrideGadgetConfig(itemKey string, itemAttr string, value string) (error, bool) {
144+
u.configLock.Lock()
145+
defer u.configLock.Unlock()
146+
147+
// get it as a pointer
148+
_, ok := u.configMap[itemKey]
149+
if !ok {
150+
return fmt.Errorf("config item %s not found", itemKey), false
151+
}
152+
153+
if u.configMap[itemKey].attrs[itemAttr] == value {
154+
return nil, false
155+
}
156+
157+
u.configMap[itemKey].attrs[itemAttr] = value
158+
u.log.Info().Str("itemKey", itemKey).Str("itemAttr", itemAttr).Str("value", value).Msg("overriding gadget config")
159+
160+
return nil, true
161+
}
162+
140163
func mountConfigFS() error {
141164
_, err := os.Stat(gadgetPath)
142165
// TODO: check if it's mounted properly

jsonrpc.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -566,9 +566,12 @@ type RPCHandler struct {
566566
func rpcSetMassStorageMode(mode string) (string, error) {
567567
logger.Info().Str("mode", mode).Msg("Setting mass storage mode")
568568
var cdrom bool
569-
if mode == "cdrom" {
569+
switch mode {
570+
case "cdrom":
570571
cdrom = true
571-
} else if mode != "file" {
572+
case "file":
573+
cdrom = false
574+
default:
572575
logger.Info().Str("mode", mode).Msg("Invalid mode provided")
573576
return "", fmt.Errorf("invalid mode: %s", mode)
574577
}
@@ -587,7 +590,7 @@ func rpcSetMassStorageMode(mode string) (string, error) {
587590
}
588591

589592
func rpcGetMassStorageMode() (string, error) {
590-
cdrom, err := getMassStorageMode()
593+
cdrom, err := getMassStorageCDROMEnabled()
591594
if err != nil {
592595
return "", fmt.Errorf("failed to get mass storage mode: %w", err)
593596
}

ui/src/routes/devices.$id.mount.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ function BrowserFileView({
414414
if (file?.name.endsWith(".iso")) {
415415
setUsbMode("CDROM");
416416
} else if (file?.name.endsWith(".img")) {
417-
setUsbMode("CDROM");
417+
setUsbMode("Disk");
418418
}
419419
};
420420

@@ -566,7 +566,7 @@ function UrlView({
566566
if (url.endsWith(".iso")) {
567567
setUsbMode("CDROM");
568568
} else if (url.endsWith(".img")) {
569-
setUsbMode("CDROM");
569+
setUsbMode("Disk");
570570
}
571571
}
572572

@@ -773,7 +773,7 @@ function DeviceFileView({
773773
if (file.name.endsWith(".iso")) {
774774
setUsbMode("CDROM");
775775
} else if (file.name.endsWith(".img")) {
776-
setUsbMode("CDROM");
776+
setUsbMode("Disk");
777777
}
778778
}
779779

@@ -1579,7 +1579,6 @@ function UsbModeSelector({
15791579
type="radio"
15801580
id="disk"
15811581
name="mountType"
1582-
disabled
15831582
checked={usbMode === "Disk"}
15841583
onChange={() => setUsbMode("Disk")}
15851584
className="h-3 w-3 border-slate-800/30 bg-white text-blue-700 transition-opacity focus:ring-blue-500 disabled:opacity-30 dark:bg-slate-800"
@@ -1588,9 +1587,6 @@ function UsbModeSelector({
15881587
<span className="text-sm font-medium leading-none text-slate-900 opacity-50 dark:text-white">
15891588
Disk
15901589
</span>
1591-
<div className="text-[10px] text-slate-500 dark:text-slate-400">
1592-
Coming soon
1593-
</div>
15941590
</div>
15951591
</label>
15961592
</div>

usb_mass_storage.go

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ func writeFile(path string, data string) error {
2626
return os.WriteFile(path, []byte(data), 0644)
2727
}
2828

29+
func getMassStorageImage() (string, error) {
30+
massStorageFunctionPath, err := gadget.GetPath("mass_storage_lun0")
31+
if err != nil {
32+
return "", fmt.Errorf("failed to get mass storage path: %w", err)
33+
}
34+
35+
imagePath, err := os.ReadFile(path.Join(massStorageFunctionPath, "file"))
36+
if err != nil {
37+
return "", fmt.Errorf("failed to get mass storage image path: %w", err)
38+
}
39+
return strings.TrimSpace(string(imagePath)), nil
40+
}
41+
2942
func setMassStorageImage(imagePath string) error {
3043
massStorageFunctionPath, err := gadget.GetPath("mass_storage_lun0")
3144
if err != nil {
@@ -39,19 +52,21 @@ func setMassStorageImage(imagePath string) error {
3952
}
4053

4154
func setMassStorageMode(cdrom bool) error {
42-
massStorageFunctionPath, err := gadget.GetPath("mass_storage_lun0")
43-
if err != nil {
44-
return fmt.Errorf("failed to get mass storage path: %w", err)
45-
}
46-
4755
mode := "0"
4856
if cdrom {
4957
mode = "1"
5058
}
51-
if err := writeFile(path.Join(massStorageFunctionPath, "lun.0", "cdrom"), mode); err != nil {
59+
60+
err, changed := gadget.OverrideGadgetConfig("mass_storage_lun0", "cdrom", mode)
61+
if err != nil {
5262
return fmt.Errorf("failed to set cdrom mode: %w", err)
5363
}
54-
return nil
64+
65+
if !changed {
66+
return nil
67+
}
68+
69+
return gadget.UpdateGadgetConfig()
5570
}
5671

5772
func onDiskMessage(msg webrtc.DataChannelMessage) {
@@ -113,20 +128,17 @@ func rpcMountBuiltInImage(filename string) error {
113128
return mountImage(imagePath)
114129
}
115130

116-
func getMassStorageMode() (bool, error) {
131+
func getMassStorageCDROMEnabled() (bool, error) {
117132
massStorageFunctionPath, err := gadget.GetPath("mass_storage_lun0")
118133
if err != nil {
119134
return false, fmt.Errorf("failed to get mass storage path: %w", err)
120135
}
121-
122136
data, err := os.ReadFile(path.Join(massStorageFunctionPath, "lun.0", "cdrom"))
123137
if err != nil {
124138
return false, fmt.Errorf("failed to read cdrom mode: %w", err)
125139
}
126-
127140
// Trim any whitespace characters. It has a newline at the end
128141
trimmedData := strings.TrimSpace(string(data))
129-
130142
return trimmedData == "1", nil
131143
}
132144

@@ -191,6 +203,36 @@ func rpcUnmountImage() error {
191203

192204
var httpRangeReader *httpreadat.RangeReader
193205

206+
func getInitialVirtualMediaState() (*VirtualMediaState, error) {
207+
cdromEnabled, err := getMassStorageCDROMEnabled()
208+
if err != nil {
209+
return nil, fmt.Errorf("failed to get mass storage cdrom enabled: %w", err)
210+
}
211+
212+
diskPath, err := getMassStorageImage()
213+
if err != nil {
214+
return nil, fmt.Errorf("failed to get mass storage image: %w", err)
215+
}
216+
217+
source := Storage
218+
// TODO: check if it's WebRTC or HTTP
219+
if diskPath == "/dev/nbd0" {
220+
source = HTTP
221+
}
222+
223+
mode := Disk
224+
if cdromEnabled {
225+
mode = CDROM
226+
}
227+
228+
return &VirtualMediaState{
229+
Source: source,
230+
Mode: mode,
231+
URL: "",
232+
Size: 0,
233+
}, nil
234+
}
235+
194236
func rpcMountWithHTTP(url string, mode VirtualMediaMode) error {
195237
virtualMediaStateMutex.Lock()
196238
if currentVirtualMediaState != nil {
@@ -204,6 +246,11 @@ func rpcMountWithHTTP(url string, mode VirtualMediaMode) error {
204246
return fmt.Errorf("failed to use http url: %w", err)
205247
}
206248
logger.Info().Str("url", url).Int64("size", n).Msg("using remote url")
249+
250+
if err := setMassStorageMode(mode == CDROM); err != nil {
251+
return fmt.Errorf("failed to set mass storage mode: %w", err)
252+
}
253+
207254
currentVirtualMediaState = &VirtualMediaState{
208255
Source: HTTP,
209256
Mode: mode,
@@ -243,6 +290,11 @@ func rpcMountWithWebRTC(filename string, size int64, mode VirtualMediaMode) erro
243290
Size: size,
244291
}
245292
virtualMediaStateMutex.Unlock()
293+
294+
if err := setMassStorageMode(mode == CDROM); err != nil {
295+
return fmt.Errorf("failed to set mass storage mode: %w", err)
296+
}
297+
246298
logger.Debug().Interface("currentVirtualMediaState", currentVirtualMediaState).Msg("currentVirtualMediaState")
247299
logger.Debug().Msg("Starting nbd device")
248300
nbdDevice = NewNBDDevice()
@@ -280,6 +332,10 @@ func rpcMountWithStorage(filename string, mode VirtualMediaMode) error {
280332
return fmt.Errorf("failed to get file info: %w", err)
281333
}
282334

335+
if err := setMassStorageMode(mode == CDROM); err != nil {
336+
return fmt.Errorf("failed to set mass storage mode: %w", err)
337+
}
338+
283339
err = setMassStorageImage(fullPath)
284340
if err != nil {
285341
return fmt.Errorf("failed to set mass storage image: %w", err)

0 commit comments

Comments
 (0)