[pve-devel] Floppy-Support

Andreas Steinel a.steinel at gmail.com
Mon Mar 16 22:15:57 CET 2015


Hi all,

I wanted the floppy support as well as others want it in the forums,
so I decided to get it to work again.

I adapted the patches from this forum post

    http://forum.proxmox.com/threads/10910-Floppy-patch

to current 3.4er branches of the corresponding packages. I fixed some
additional minor bugs corresponding to the previous patches, yet I
couldn't get the boot order right. Manual setting the boot order
works, yet the bootindex stuff, which is generated by the code does
not work for floppy (bootindex is not a valid keyword).

Nevertheless, I attached the patches (one patch per git-repository, no
format patch) and maybe we can the boot-order stuff working together.
Maybe Romain_Orange will - as well as I - agree to the contributor
agreement.

Best regards from Saarbrücken,
Andreas
-------------- next part --------------
diff --git a/www/manager/Makefile b/www/manager/Makefile
index 6876c74..35db90f 100644
--- a/www/manager/Makefile
+++ b/www/manager/Makefile
@@ -62,6 +62,7 @@ JSSRC= 				                 	\
 	form/BackupModeSelector.js			\
 	form/ScsiHwSelector.js				\
 	form/FirewallPolicySelector.js			\
+	form/FloppySelector.js              \
 	dc/Tasks.js					\
 	dc/Log.js					\
 	panel/StatusPanel.js				\
@@ -139,6 +140,8 @@ JSSRC= 				                 	\
 	qemu/SnapshotTree.js				\
 	qemu/Config.js					\
 	qemu/CreateWizard.js				\
+	qemu/FloppyInputPanel.js        \
+	qemu/FloppyEdit.js        \
 	openvz/StatusView.js				\
 	openvz/Summary.js				\
 	openvz/RessourceEdit.js				\
diff --git a/www/manager/Utils.js b/www/manager/Utils.js
index c293b06..3a5bb9c 100644
--- a/www/manager/Utils.js
+++ b/www/manager/Utils.js
@@ -715,6 +715,7 @@ Ext.define('PVE.Utils', { statics: {
     backupFileText: gettext('VZDump backup file'),
     vztmplText: gettext('OpenVZ template'),
     isoImageText: gettext('ISO image'),
+    flpText: gettext('Floppy image'),
     containersText: gettext('OpenVZ Container'),
 
     format_expire: function(date) {
@@ -777,6 +778,8 @@ Ext.define('PVE.Utils', { statics: {
 		cta.push(PVE.Utils.vztmplText);
 	    } else if (ct === 'iso') {
 		cta.push(PVE.Utils.isoImageText);
+	    } else if (ct === 'flp') {
+		cta.push(PVE.Utils.flpText);
 	    } else if (ct === 'rootdir') {
 		cta.push(PVE.Utils.containersText);
 	    }
diff --git a/www/manager/form/ContentTypeSelector.js b/www/manager/form/ContentTypeSelector.js
index 0c74524..965fb9a 100644
--- a/www/manager/form/ContentTypeSelector.js
+++ b/www/manager/form/ContentTypeSelector.js
@@ -10,7 +10,7 @@ Ext.define('PVE.form.ContentTypeSelector', {
 	me.data = [];
 
 	if (me.cts === undefined) {
-	    me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir'];
+	    me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir','flp'];
 	}
 
 	Ext.Array.each(me.cts, function(ct) {
diff --git a/www/manager/form/FloppySelector.js b/www/manager/form/FloppySelector.js
new file mode 100644
index 0000000..1bf2eef
--- /dev/null
+++ b/www/manager/form/FloppySelector.js
@@ -0,0 +1,89 @@
+Ext.define('PVE.form.FloppySelector', {
+    extend: 'Ext.form.FieldContainer',
+    alias: ['widget.PVE.form.FloppySelector'],
+   
+    statics: {
+    maxIds: {
+        floppy: 2
+    }
+    },
+
+    vmconfig: {}, // used to check for existing devices
+
+    setVMConfig: function(vmconfig, autoSelect) {
+    var me = this;
+
+    me.vmconfig = Ext.apply({}, vmconfig);
+    if (autoSelect) {
+        var clist = ['floppy'];
+
+        Ext.Array.each(clist, function(controller) {
+        var confid, i;
+
+        me.down('field[name=controller]').setValue(controller);
+        for (i = 0; i <= PVE.form.ControllerSelector.maxIds[controller]; i++) {
+            confid = controller + i.toString();
+            if (!Ext.isDefined(me.vmconfig[confid])) {
+            me.down('field[name=deviceid]').setValue(i);
+            return false; // break
+            }
+        }
+        });
+    }
+    me.down('field[name=deviceid]').validate();
+    },
+
+    initComponent: function() {
+    var me = this;
+
+    Ext.apply(me, {
+        fieldLabel: 'Bus/Device',
+        layout: 'hbox',
+        height: 22, // hack: set to same height as other fields
+        defaults: {
+                flex: 1,
+                hideLabel: true
+        },
+        items: [
+        {
+            xtype: 'PVE.form.BusTypeSelector',
+            name: 'controller',
+            value: 'floppy',
+            allowBlank: false,
+            listeners: {
+            change: function(t, value) {
+                if (!me.rendered || !value) {
+                return;
+                }
+                var field = me.down('field[name=deviceid]');
+                field.setMaxValue(PVE.form.ControllerSelector.maxIds[value]);
+                field.validate();
+            }
+            }
+        },
+        {
+            xtype: 'numberfield',
+            name: 'deviceid',
+            minValue: 0,
+            maxValue: PVE.form.ControllerSelector.maxIds.floppy,
+            value: '0',
+            validator: function(value) {
+            /*jslint confusion: true */
+            if (!me.rendered) {
+                return;
+            }
+            var field = me.down('field[name=controller]');
+            var controller = field.getValue();
+            var confid = controller + value;
+            if (Ext.isDefined(me.vmconfig[confid])) {
+                return "This device is already in use.";
+            }
+            return true;
+            }
+        }
+        ]
+    });
+
+    me.callParent();
+    }
+});
diff --git a/www/manager/qemu/BootOrderEdit.js b/www/manager/qemu/BootOrderEdit.js
index 9601313..1695025 100644
--- a/www/manager/qemu/BootOrderEdit.js
+++ b/www/manager/qemu/BootOrderEdit.js
@@ -73,9 +73,9 @@ Ext.define('PVE.qemu.BootOrderPanel', {
 	if (sel1 !== 'n' && (sel2 !== 'n')) {
 	    list.push(['n', gettext('Network')]);
 	}
-	//if (sel1 !== 'a' && (sel2 !== 'a')) {
-	//    list.push(['a', 'Floppy']);
-	//}
+	if (sel1 !== 'a' && (sel2 !== 'a')) {
+	    list.push(['a', 'Floppy']);
+	}
 	
 	if (includeNone) {
 	    list.push(['', PVE.Utils.noneText]);
diff --git a/www/manager/qemu/FloppyEdit.js b/www/manager/qemu/FloppyEdit.js
new file mode 100644
index 0000000..1ffb039
--- /dev/null
+++ b/www/manager/qemu/FloppyEdit.js
@@ -0,0 +1,42 @@
+Ext.define('PVE.qemu.FloppyEdit', {
+    extend: 'PVE.window.Edit',
+
+    initComponent : function() {
+    var me = this;
+
+    var nodename = me.pveSelNode.data.node;
+    if (!nodename) {
+        throw "no node name specified";        
+    }
+
+    me.create = me.confid ? false : true;
+
+    var ipanel = Ext.create('PVE.qemu.FloppyInputPanel', {
+        confid: me.confid,
+        nodename: nodename
+    });
+
+    Ext.applyIf(me, {
+        subject: 'Floppy Drive',
+        items: [ ipanel ]
+    });
+
+    me.callParent();
+    
+    me.load({
+        success:  function(response, options) {
+        ipanel.setVMConfig(response.result.data);
+        if (me.confid) {
+            var value = response.result.data[me.confid];
+            var drive = PVE.Parser.parseQemuDrive(me.confid, value);
+            if (!drive) {
+            Ext.Msg.alert('Error', 'Unable to parse drive options');
+            me.close();
+            return;
+            }
+            ipanel.setDrive(drive);
+        }
+        }
+    });
+    }
+});
diff --git a/www/manager/qemu/FloppyInputPanel.js b/www/manager/qemu/FloppyInputPanel.js
new file mode 100644
index 0000000..184764f
--- /dev/null
+++ b/www/manager/qemu/FloppyInputPanel.js
@@ -0,0 +1,136 @@
+Ext.define('PVE.qemu.FloppyInputPanel', {
+    extend: 'PVE.panel.InputPanel',
+    alias: 'widget.PVE.qemu.FloppyInputPanel',
+
+    insideWizard: false,
+
+    onGetValues: function(values) {
+    var me = this;
+
+    var confid = me.confid || (values.controller + values.deviceid);
+    
+    me.drive.media = 'disk';
+    if (values.mediaType === 'flp') {
+        me.drive.file = values.cdimage;
+    }else {
+        me.drive.file = 'none';
+    }
+
+    var params = {};
+        
+    params[confid] = PVE.Parser.printQemuDrive(me.drive);
+    
+    return params;    
+    },
+
+    setVMConfig: function(vmconfig) {
+    var me = this;
+
+    if (me.bussel) {
+        me.bussel.setVMConfig(vmconfig, true);
+    }
+    },
+
+    setDrive: function(drive) {
+    var me = this;
+
+    var values = {};
+    if (drive.file === 'flp') {
+        values.mediaType = 'flp';
+    } else if (drive.file === 'none') {
+        values.mediaType = 'none';
+    } else {
+        values.mediaType = 'flp';
+        var match = drive.file.match(/^([^:]+):/);
+        if (match) {
+        values.cdstorage = match[1];
+        values.cdimage = drive.file;
+        }
+    }
+
+    me.drive = drive;
+
+    me.setValues(values);
+    },
+
+    setNodename: function(nodename) {
+    var me = this;
+
+    me.cdstoragesel.setNodename(nodename);
+    me.cdfilesel.setStorage(undefined, nodename);
+    },
+
+    initComponent : function() {
+    var me = this;
+
+    me.drive = {};
+
+    var items = [];
+
+    if (!me.confid) {
+        me.bussel = Ext.createWidget('PVE.form.FloppySelector');
+        items.push(me.bussel);
+    }
+
+    items.push({
+        xtype: 'radiofield',
+        name: 'mediaType',
+        inputValue: 'flp',
+        boxLabel: 'Use Floppy flp image file',
+        checked: true,
+        listeners: {
+        change: function(f, value) {
+            if (!me.rendered) {
+            return;
+            }
+            me.down('field[name=cdstorage]').setDisabled(!value);
+            me.down('field[name=cdimage]').setDisabled(!value);
+            me.down('field[name=cdimage]').validate();
+        }
+        }
+    });
+
+    me.cdfilesel = Ext.create('PVE.form.FileSelector', {
+        name: 'cdimage',
+        nodename: me.nodename,
+        storageContent: 'flp',
+        fieldLabel: 'Flp Image',
+        labelAlign: 'right',
+        allowBlank: false
+    });
+    
+    me.cdstoragesel = Ext.create('PVE.form.StorageSelector', {
+        name: 'cdstorage',
+        nodename: me.nodename,
+        fieldLabel: gettext('Storage'),
+        labelAlign: 'right',
+        storageContent: 'flp',
+        allowBlank: false,
+        autoSelect: me.insideWizard,
+        listeners: {
+        change: function(f, value) {
+            me.cdfilesel.setStorage(value);
+        }
+        }
+    });
+
+    items.push(me.cdstoragesel);
+    items.push(me.cdfilesel);
+
+    items.push({
+        xtype: 'radiofield',
+        name: 'mediaType',
+        inputValue: 'none',
+        boxLabel: 'Do not use any media'
+    });
+
+    if (me.insideWizard) {
+        me.column1 = items;
+    } else {
+        me.items = items;
+    }
+
+    me.callParent();
+    }
+});
+
diff --git a/www/manager/qemu/HardwareView.js b/www/manager/qemu/HardwareView.js
index 43f6c1e..40b320e 100644
--- a/www/manager/qemu/HardwareView.js
+++ b/www/manager/qemu/HardwareView.js
@@ -151,6 +151,16 @@ Ext.define('PVE.qemu.HardwareView', {
 		cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
 	    };
 	}
+    for (i = 0; i < 2; i++) {
+         confid = "floppy" + i;
+         rows[confid] = {
+         group: 1,
+         tdCls: 'pve-itype-icon-storage',
+         editor: 'PVE.qemu.FloppyEdit',
+         header: gettext('Floppy Drive') + ' (' + confid +')',
+         cdheader: gettext('Floppy Drive') + ' (' + confid +')'
+         };
+     }
 	for (i = 0; i < 16; i++) {
 	    confid = "virtio" + i;
 	    rows[confid] = {
@@ -434,6 +444,19 @@ Ext.define('PVE.qemu.HardwareView', {
 				    win.show();
 				}
 			    },
+                {
+                text: gettext('Floppy Drive'),
+                iconCls: 'pve-itype-icon-storage',
+                //disabled: !caps.vms['VM.Config.Floppy'],
+                handler: function() {
+                    var win = Ext.create('PVE.qemu.FloppyEdit', {
+                    url: '/api2/extjs/' + baseurl,
+                    pveSelNode: me.pveSelNode
+                    });
+                    win.on('destroy', reload);
+                    win.show();
+                }
+                },
 			    {
 				text: gettext('Network Device'),
 				iconCls: 'pve-itype-icon-network',
diff --git a/www/manager/storage/ContentView.js b/www/manager/storage/ContentView.js
index fcbb0ac..16aad03 100644
--- a/www/manager/storage/ContentView.js
+++ b/www/manager/storage/ContentView.js
@@ -184,7 +184,7 @@ Ext.define('PVE.storage.Upload', {
 	    items: [
 		{
 		    xtype: 'pveContentTypeSelector',
-		    cts: ['iso', 'backup', 'vztmpl'],
+		    cts: ['iso', 'backup', 'vztmpl', 'flp'],
 		    fieldLabel: gettext('Content'),
 		    name: 'content',
 		    value: 'iso'
-------------- next part --------------
diff --git a/PVE/API2/Storage/Config.pm b/PVE/API2/Storage/Config.pm
index 27b3a55..bcb2edd 100755
--- a/PVE/API2/Storage/Config.pm
+++ b/PVE/API2/Storage/Config.pm
@@ -17,7 +17,7 @@ use PVE::RESTHandler;
 
 use base qw(PVE::RESTHandler);
 
-my @ctypes = qw(images vztmpl iso backup);
+my @ctypes = qw(images vztmpl iso backup flp);
 
 my $storage_type_enum = PVE::Storage::Plugin->lookup_types();
 
diff --git a/PVE/API2/Storage/Content.pm b/PVE/API2/Storage/Content.pm
index 605e455..dd15208 100644
--- a/PVE/API2/Storage/Content.pm
+++ b/PVE/API2/Storage/Content.pm
@@ -77,6 +77,8 @@ __PACKAGE__->register_method ({
 		$data = PVE::Storage::vdisk_list ($cfg, $storeid, $param->{vmid});
 	    } elsif ($ct eq 'iso') {
 		$data = PVE::Storage::template_list ($cfg, $storeid, 'iso');
+	    } elsif ($ct eq 'flp') {
+		$data = PVE::Storage::template_list ($cfg, $storeid, 'flp');
 	    } elsif ($ct eq 'vztmpl') {
 		$data = PVE::Storage::template_list ($cfg, $storeid, 'vztmpl');
 	    } elsif ($ct eq 'backup') {
diff --git a/PVE/API2/Storage/Status.pm b/PVE/API2/Storage/Status.pm
index d9326b7..0051345 100644
--- a/PVE/API2/Storage/Status.pm
+++ b/PVE/API2/Storage/Status.pm
@@ -350,6 +350,11 @@ __PACKAGE__->register_method ({
 		raise_param_exc({ filename => "missing '.iso' extension" });
 	    }
 	    $path = PVE::Storage::get_iso_dir($cfg, $param->{storage});
+	} elsif ($content eq 'flp') {
+	    if ($filename !~ m![^/]+\.[Ff][Ll][Pp]$!) {
+		raise_param_exc({ filename => "missing '.flp' extension" });
+	    }
+	    $path = PVE::Storage::get_flp_dir($cfg, $param->{storage});
 	} elsif ($content eq 'vztmpl') {
 	    if ($filename !~ m![^/]+\.tar\.gz$!) {
 		raise_param_exc({ filename => "missing '.tar.gz' extension" });
diff --git a/PVE/Storage.pm b/PVE/Storage.pm
index e46bc77..afe025f 100755
--- a/PVE/Storage.pm
+++ b/PVE/Storage.pm
@@ -251,6 +251,15 @@ sub get_iso_dir {
     return $plugin->get_subdir($scfg, 'iso');
 }
 
+sub get_flp_dir {
+    my ($cfg, $storeid) = @_;
+
+    my $scfg = storage_config($cfg, $storeid);
+    my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+
+    return $plugin->get_subdir($scfg, 'flp');
+}
+
 sub get_vztmpl_dir {
     my ($cfg, $storeid) = @_;
 
@@ -348,6 +357,7 @@ sub path_to_volume_id {
 	my $tmpldir = $plugin->get_subdir($scfg, 'vztmpl');
 	my $backupdir = $plugin->get_subdir($scfg, 'backup');
 	my $privatedir = $plugin->get_subdir($scfg, 'rootdir');
+	my $flpdir = $plugin->get_subdir($scfg, 'flp');
 
 	if ($path =~ m!^$imagedir/(\d+)/([^/\s]+)$!) {
 	    my $vmid = $1;
@@ -364,6 +374,9 @@ sub path_to_volume_id {
 	} elsif ($path =~ m!^$isodir/([^/]+\.[Ii][Ss][Oo])$!) {
 	    my $name = $1;
 	    return ('iso', "$sid:iso/$name");
+	} elsif ($path =~ m!^$flpdir/([^/]+\.[Ff][Ll][Pp])$!) {
+	    my $name = $1;
+	    return ('flp', "$sid:flp/$name");
 	} elsif ($path =~ m!^$tmpldir/([^/]+\.tar\.gz)$!) {
 	    my $name = $1;
 	    return ('vztmpl', "$sid:vztmpl/$name");
@@ -611,7 +624,7 @@ sub template_list {
     my ($cfg, $storeid, $tt) = @_;
 
     die "unknown template type '$tt'\n"
-	if !($tt eq 'iso' || $tt eq 'vztmpl' || $tt eq 'backup');
+	if !($tt eq 'iso' || $tt eq 'vztmpl' || $tt eq 'backup' || $tt eq 'flp' );
 
     my $ids = $cfg->{ids};
 
@@ -632,6 +645,7 @@ sub template_list {
 	next if $tt eq 'iso' && !$scfg->{content}->{iso};
 	next if $tt eq 'vztmpl' && !$scfg->{content}->{vztmpl};
 	next if $tt eq 'backup' && !$scfg->{content}->{backup};
+	next if $tt eq 'flp' && !$scfg->{content}->{flp};
 
 	activate_storage($cfg, $sid);
 
@@ -649,6 +663,11 @@ sub template_list {
 
 		    $info = { volid => "$sid:iso/$1", format => 'iso' };
 
+		} elsif ($tt eq 'flp') {
+		    next if $fn !~ m!/([^/]+\.[Ff][Ll][Pp])$!;
+
+		    $info = { volid => "$sid:flp/$1", format => 'flp' };
+
 		} elsif ($tt eq 'vztmpl') {
 		    next if $fn !~ m!/([^/]+\.tar\.gz)$!;
 
diff --git a/PVE/Storage/DirPlugin.pm b/PVE/Storage/DirPlugin.pm
index 41842f2..e74a987 100644
--- a/PVE/Storage/DirPlugin.pm
+++ b/PVE/Storage/DirPlugin.pm
@@ -16,7 +16,7 @@ sub type {
 
 sub plugindata {
     return {
-	content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1, backup => 1, none => 1 },
+	content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1, backup => 1, flp => 1, none => 1 },
 		     { images => 1,  rootdir => 1 }],
 	format => [ { raw => 1, qcow2 => 1, vmdk => 1 } , 'raw' ],
     };
diff --git a/PVE/Storage/Plugin.pm b/PVE/Storage/Plugin.pm
index 3eb99f2..51d747d 100644
--- a/PVE/Storage/Plugin.pm
+++ b/PVE/Storage/Plugin.pm
@@ -364,6 +364,8 @@ sub parse_volname {
 	return ('images', $name, $vmid, undef, undef, $isBase);
     } elsif ($volname =~ m!^iso/([^/]+\.[Ii][Ss][Oo])$!) {
 	return ('iso', $1);
+    } elsif ($volname =~ m!^flp/([^/]+\.[Ff][Ll][Pp])$!) {
+	return ('flp', $1);
     } elsif ($volname =~ m!^vztmpl/([^/]+\.tar\.gz)$!) {
 	return ('vztmpl', $1);
     } elsif ($volname =~ m!^rootdir/(\d+)$!) {
@@ -382,6 +384,7 @@ sub parse_volname {
 my $vtype_subdirs = {
     images => 'images',
     rootdir => 'private',
+    flp => 'flp',
     iso => 'template/iso',
     vztmpl => 'template/cache',
     backup => 'dump',
-------------- next part --------------
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 2720540..dd4eb7e 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -489,6 +489,7 @@ my $MAX_UNUSED_DISKS = 8;
 my $MAX_HOSTPCI_DEVICES = 4;
 my $MAX_SERIAL_PORTS = 4;
 my $MAX_PARALLEL_PORTS = 3;
+my $MAX_FLOPPY_DEVICES = 2;
 my $MAX_NUMA = 8;
 my $MAX_MEM = 4194304;
 my $STATICMEM = 1024;
@@ -643,6 +644,18 @@ Experimental: user reported problems with this option.
 EODESCR
 };
 
+my $floppydesc= {
+      optional => 1,
+      type => 'string', format => 'pve-qm-drive',
+      typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads]',
+      description => <<EODESCR,
+
+       Note : OB floppy plugin
+
+EODESCR
+};
+PVE::JSONSchema::register_standard_option("pve-qm-floppy", $floppydesc);
+
 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++)  {
     $confdesc->{"parallel$i"} = $paralleldesc;
 }
@@ -678,6 +691,10 @@ for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++)  {
 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++)  {
     $confdesc->{"usb$i"} = $usbdesc;
 }
+for (my $i = 0; $i < $MAX_FLOPPY_DEVICES; $i++)  {
+      $drivename_hash->{"floppy$i"} = 1;
+      $confdesc->{"floppy$i"} = $floppydesc;
+}
 
 my $unuseddesc = {
     optional => 1,
@@ -729,10 +746,13 @@ my $kernel_has_vhost_net = -c '/dev/vhost-net';
 
 sub disknames {
     # order is important - used to autoselect boot disk
-    return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
+    return (
+            (map { "floppy$_" } (0 .. ($MAX_FLOPPY_DEVICES - 1))),
+            (map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
             (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
             (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
-            (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))));
+            (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1)))
+           );
 }
 
 sub valid_drivename {
@@ -1197,6 +1217,7 @@ sub print_drivedevice_full {
     } elsif ($drive->{interface} eq 'usb') {
 	die "implement me";
 	#  -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
+    } elsif ($drive->{interface} eq 'floppy') {
     } else {
 	die "unsupported interface type";
     }
@@ -1256,6 +1277,10 @@ sub print_drive_full {
 
     my $pathinfo = $path ? "file=$path," : '';
 
+    if($drive->{interface} eq 'floppy'){
+        return "${pathinfo}index=$drive->{index},if=floppy";
+    }
+    
     return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
 }
 
@@ -3099,6 +3124,10 @@ sub config_to_command {
 		$drive->{bootindex} = $bootindex_hash->{c} if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds);
 		$bootindex_hash->{c} += 1;
 	    }
+	    if ($bootindex_hash->{a}) {
+		$drive->{bootindex} = $bootindex_hash->{a} if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds);
+		$bootindex_hash->{a} += 1;
+        }
 	}
 
         if ($drive->{interface} eq 'scsi') {
@@ -3119,7 +3148,9 @@ sub config_to_command {
 
 	my $drive_cmd = print_drive_full($storecfg, $vmid, $drive);
 	push @$devices, '-drive',$drive_cmd;
-	push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges);
+	if($drive->{interface} ne 'floppy'){
+		push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges);
+    }
     });
 
     for (my $i = 0; $i < $MAX_NETS; $i++) {


More information about the pve-devel mailing list