@@ -74,6 +74,7 @@ impl Drop for StatusFile {
75const PROVISION_SCRIPT: &str = include_str!("provision.sh");
75const PROVISION_SCRIPT: &str = include_str!("provision.sh");
76const PROVISION_SCRIPT_NAME: &str = "provision.sh";
76const PROVISION_SCRIPT_NAME: &str = "provision.sh";
77+const RESIZE_DISK_SCRIPT: &str = include_str!("resize_disk.sh");
77const DEFAULT_RAW_NAME: &str = "default.raw";
78const DEFAULT_RAW_NAME: &str = "default.raw";
78const INSTANCE_RAW_NAME: &str = "instance.raw";
79const INSTANCE_RAW_NAME: &str = "instance.raw";
79const BASE_DISK_RAW_NAME: &str = "disk.raw";
80const BASE_DISK_RAW_NAME: &str = "disk.raw";
@@ -166,6 +167,7 @@ fn expand_tilde_path(value: &str) -> PathBuf {
166pub struct VmArg {
167pub struct VmArg {
167 pub cpu_count: usize,
168 pub cpu_count: usize,
168 pub ram_bytes: u64,
169 pub ram_bytes: u64,
170+ pub disk_bytes: u64,
169 pub no_default_mounts: bool,
171 pub no_default_mounts: bool,
170 pub mounts: Vec<String>,
172 pub mounts: Vec<String>,
@@ -230,7 +232,15 @@ where
230 std::slice::from_ref(&mise_directory_share),
232 std::slice::from_ref(&mise_directory_share),
231 Some(&status_file),
233 Some(&status_file),
233− ensure_instance_disk(&instance_raw, &default_raw, Some(&status_file))?;
235+ let _ = ensure_instance_disk(
241+ let base_size = fs::metadata(&default_raw)?.len();
242+ let instance_size = fs::metadata(&instance_raw)?.len();
243+ let needs_resize = instance_size > base_size;
234 let disk_path = instance_raw;
244 let disk_path = instance_raw;
236 let mut login_actions = Vec::new();
246 let mut login_actions = Vec::new();
@@ -263,6 +273,11 @@ where
263 directory_shares.push(DirectoryShare::from_mount_spec(spec)?);
273 directory_shares.push(DirectoryShare::from_mount_spec(spec)?);
277+ let resize_cmd = script_command_from_content("resize_disk", RESIZE_DISK_SCRIPT)?;
278+ login_actions.push(Send(resize_cmd));
266 if let Some(motd_action) = motd_login_action(&directory_shares) {
281 if let Some(motd_action) = motd_login_action(&directory_shares) {
267 login_actions.push(motd_action);
282 login_actions.push(motd_action);
@@ -559,19 +574,51 @@ fn ensure_default_image(
559fn ensure_instance_disk(
574fn ensure_instance_disk(
560 instance_raw: &Path,
575 instance_raw: &Path,
561 template_raw: &Path,
576 template_raw: &Path,
562 status: Option<&StatusFile>,
578 status: Option<&StatusFile>,
563−) -> Result<(), Box<dyn std::error::Error>> {
579+) -> Result<bool, Box<dyn std::error::Error>> {
564 if instance_raw.exists() {
580 if instance_raw.exists() {
581+ let current_size = fs::metadata(instance_raw)?.len();
582+ if current_size != target_bytes {
583+ let current_gb = current_size as f64 / (1024.0 * 1024.0 * 1024.0);
584+ let target_gb = target_bytes as f64 / (1024.0 * 1024.0 * 1024.0);
586+ current_bytes = current_size,
588+ "instance disk size does not match config (current {:.2} GB, config {:.2} GB); disk_gb applies only on init. Run `vibebox reset` to recreate or set disk_gb to match; using existing disk.",
565− return Ok(());
593+ return Ok(false);
596+ let template_size = fs::metadata(template_raw)?.len();
597+ if target_bytes < template_size {
599+ "Requested disk size {} bytes is smaller than base image size {} bytes",
600+ target_bytes, template_size
604+ let target_size = target_bytes;
605+ let needs_resize = target_size > template_size;
568 if let Some(status) = status {
607 if let Some(status) = status {
569 status.update("creating instance disk...");
608 status.update("creating instance disk...");
571 tracing::info!(path = %template_raw.display(), "creating instance disk");
610 tracing::info!(path = %template_raw.display(), "creating instance disk");
572 std::fs::create_dir_all(instance_raw.parent().unwrap())?;
611 std::fs::create_dir_all(instance_raw.parent().unwrap())?;
612+ if target_size == template_size {
573− fs::copy(template_raw, instance_raw)?;
613+ fs::copy(template_raw, instance_raw)?;
574− Ok(())
614+ return Ok(needs_resize);
617+ let mut dst = std::fs::File::create(instance_raw)?;
618+ dst.set_len(target_size)?;
619+ let mut src = std::fs::File::open(template_raw)?;
620+ std::io::copy(&mut src, &mut dst)?;
577pub struct IoContext {
624pub struct IoContext {