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
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::path::PathBuf;

use serde::Deserialize;
use serde::Serialize;

pub(crate) mod sys;

pub mod commands;
pub mod constants;
mod device;

pub use device::Controller;
pub use device::DiskConfig;

fn scsi_option_lock_default() -> bool {
    true
}
fn scsi_option_block_size_default() -> u32 {
    512
}

/// Parameters for setting up a SCSI device.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, serde_keyvalue::FromKeyValues)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub struct ScsiOption {
    // Path to the SCSI image.
    pub path: PathBuf,
    // Indicates whether the device is ready only.
    #[serde(default, rename = "ro")]
    pub read_only: bool,
    /// Whether to lock the disk files. Uses flock on Unix and FILE_SHARE_* flags on Windows.
    #[serde(default = "scsi_option_lock_default")]
    pub lock: bool,
    // The block size of the device.
    #[serde(default = "scsi_option_block_size_default")]
    pub block_size: u32,
    /// Whether this scsi device should be the root device. Can only be set once. Only useful for
    /// adding specific command-line options.
    #[serde(default)]
    pub root: bool,
}

#[cfg(test)]
mod tests {
    use std::path::Path;

    use serde_keyvalue::from_key_values;

    use super::*;

    #[test]
    fn parse_scsi_options() {
        let scsi_option = from_key_values::<ScsiOption>("/path/to/image").unwrap();
        assert_eq!(
            scsi_option,
            ScsiOption {
                path: Path::new("/path/to/image").to_path_buf(),
                read_only: false,
                lock: scsi_option_lock_default(),
                block_size: 512,
                root: false,
            }
        );

        let scsi_option = from_key_values::<ScsiOption>("/path/to/image,ro").unwrap();
        assert_eq!(
            scsi_option,
            ScsiOption {
                path: Path::new("/path/to/image").to_path_buf(),
                read_only: true,
                lock: scsi_option_lock_default(),
                block_size: 512,
                root: false,
            }
        );

        let scsi_option = from_key_values::<ScsiOption>("/path/to/image,block-size=1024").unwrap();
        assert_eq!(
            scsi_option,
            ScsiOption {
                path: Path::new("/path/to/image").to_path_buf(),
                read_only: false,
                lock: scsi_option_lock_default(),
                block_size: 1024,
                root: false,
            }
        );

        let scsi_option =
            from_key_values::<ScsiOption>("/path/to/image,block-size=1024,root").unwrap();
        assert_eq!(
            scsi_option,
            ScsiOption {
                path: Path::new("/path/to/image").to_path_buf(),
                read_only: false,
                lock: scsi_option_lock_default(),
                block_size: 1024,
                root: true,
            }
        );
    }
}