Floppy patch

R

Romain_Orange

Guest
Bonjour,

For my business, i have made a floppy patch on Proxmox 2.1.

With this patch, you can add "flp" directory, download "flp" files into and, in the same way of cdrom devices, you can create floppy devices and put flp into.

The code is a little bit dirty but, it works fine.

You can find the patch below.

QemuServer.diff :

Code:
--- QemuServer.pm.OLD    2012-08-22 17:38:46.000000000 +0200
+++ QemuServer.pm    2012-08-17 09:53:06.000000000 +0200
@@ -401,6 +401,7 @@
 my $MAX_HOSTPCI_DEVICES = 2;
 my $MAX_SERIAL_PORTS = 4;
 my $MAX_PARALLEL_PORTS = 3;
+my $MAX_FLOPPY_DEVICES = 2;
 
 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000',  'pcnet',  'virtio',
               'ne2k_isa', 'i82551', 'i82557b', 'i82559er'];
@@ -536,6 +537,18 @@
 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;
 }
@@ -571,6 +584,10 @@
 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,
@@ -625,6 +642,7 @@
     return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
             (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
             (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
+            (map { "floppy$_" } (0 .. ($MAX_FLOPPY_DEVICES - 1))),
             (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))));
 }
 
@@ -987,7 +1005,9 @@
     } 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
-    } else {
+    } elsif ($drive->{interface} eq 'floppy') {
+         
+    }else {
     die "unsupported interface type";
     }
 
@@ -1025,6 +1045,10 @@
 
     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";
 }
 
@@ -2256,7 +2280,9 @@
         }
 
     push @$cmd, '-drive',print_drive_full($storecfg, $vmid, $drive);
-    push @$cmd, '-device',print_drivedevice_full($storecfg,$vmid, $drive);
+    if($drive->{interface} ne 'floppy'){
+        push @$cmd, '-device',print_drivedevice_full($storecfg,$vmid, $drive);
+    }
     });
 
     push @$cmd, '-m', $conf->{memory} || $defaults->{memory};

Storage.diff :

Code:
--- Storage.pm.OLD    2012-08-22 17:38:58.000000000 +0200
+++ Storage.pm    2012-08-23 13:55:31.000000000 +0200
@@ -143,7 +143,7 @@
     shared => 0,
     disable => 0,
         maxfiles => 0,
-    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' ],
     },
@@ -723,6 +723,15 @@
     return $isodir;
 }
 
+sub get_flp_dir {
+     my ($cfg, $storeid) = @_;
+
+     my $isodir =  $cfg->{ids}->{$storeid}->{path};
+     $isodir .= '/template/flp';
+
+     return $isodir;
+}
+
 sub get_vztmpl_dir {
     my ($cfg, $storeid) = @_;
 
@@ -964,7 +973,9 @@
     return ('image', $name, $vmid);
     } elsif ($volname =~ m!^iso/([^/]+\.[Ii][Ss][Oo])$!) {
     return ('iso', $1);
-    } elsif ($volname =~ m!^vztmpl/([^/]+\.tar\.gz)$!) {
+    } elsif ($volname =~ m!^flp/([^/]+\.[Ff][Ll][Pp])$!) {
+     return ('flp', $1);
+    }elsif ($volname =~ m!^vztmpl/([^/]+\.tar\.gz)$!) {
     return ('vztmpl', $1);
     } elsif ($volname =~ m!^rootdir/(\d+)$!) {
     return ('rootdir', $1, $1);
@@ -1073,6 +1084,7 @@
 
     my $imagedir = get_image_dir($cfg, $storeid, $vmid);
     my $isodir = get_iso_dir($cfg, $storeid);
+    my $flpdir = get_flp_dir($cfg, $storeid);
     my $tmpldir = get_vztmpl_dir($cfg, $storeid);
     my $backupdir = get_backup_dir($cfg, $storeid);
     my $privatedir = get_private_dir($cfg, $storeid);
@@ -1081,6 +1093,8 @@
         $path = "$imagedir/$name";
     } elsif ($vtype eq 'iso') {
         $path = "$isodir/$name";
+    } elsif ($vtype eq 'flp'){
+         $path = "$flpdir/$name";
     } elsif ($vtype eq 'vztmpl') {
         $path = "$tmpldir/$name";
     } elsif ($vtype eq 'rootdir') {
@@ -1512,7 +1526,7 @@
 sub template_list {
     my ($cfg, $storeid, $tt) = @_;
 
-    die "unknown template type '$tt'\n" if !($tt eq 'iso' || $tt eq 'vztmpl' || $tt eq 'backup');
+    die "unknown template type '$tt'\n" if !($tt eq 'iso' || $tt eq 'vztmpl' || $tt eq 'backup' || $tt eq 'flp');
 
     my $ids = $cfg->{ids};
 
@@ -1533,6 +1547,7 @@
     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);
 
@@ -1541,7 +1556,9 @@
         my $path;
         if ($tt eq 'iso') {
         $path = get_iso_dir($cfg, $sid);
-        } elsif ($tt eq 'vztmpl') {
+        } elsif ($tt eq 'flp') {
+        $path = get_flp_dir($cfg, $sid);
+        }elsif ($tt eq 'vztmpl') {
         $path = get_vztmpl_dir($cfg, $sid);
         } elsif ($tt eq 'backup') {
         $path = get_backup_dir($cfg, $sid);
@@ -1558,6 +1575,11 @@
 
             $info = { volid => "$sid:iso/$1", format => 'iso' };
 
+        }if ($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)$!;

Config.diff

Code:
--- Config.pm.sav    2012-08-23 16:33:19.000000000 +0200
+++ Config.pm    2012-08-23 13:14:24.000000000 +0200
@@ -15,7 +15,7 @@
 
 use base qw(PVE::RESTHandler);
 
-my @ctypes = qw(images vztmpl iso backup);
+my @ctypes = qw(images vztmpl iso backup flp);
 
 my $storage_type_enum = ['dir', 'nfs', 'lvm', 'iscsi'];

Content.diff :

Code:
--- Content.pm.sav    2012-08-23 16:33:07.000000000 +0200
+++ Content.pm    2012-08-23 14:28:13.000000000 +0200
@@ -73,7 +73,9 @@
         $data = PVE::Storage::vdisk_list ($cfg, $storeid, $param->{vmid});
         } elsif ($ct eq 'iso') {
         $data = PVE::Storage::template_list ($cfg, $storeid, 'iso');
-        } elsif ($ct eq 'vztmpl') {
+        } 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') {
         $data = PVE::Storage::template_list ($cfg, $storeid, 'backup');

Status.diff

Code:
--- Status.pm.sav    2012-08-23 16:32:59.000000000 +0200
+++ Status.pm    2012-08-23 14:36:24.000000000 +0200
@@ -319,6 +319,13 @@
         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" });

pvemanagerlib.diff

Code:
--- pvemanagerlib.js.OLD    2012-08-22 17:39:32.000000000 +0200
+++ pvemanagerlib.js    2012-08-27 09:35:10.000000000 +0200
@@ -641,6 +641,8 @@
         cta.push('Templates');
         } else if (ct === 'iso') {
         cta.push('ISO');
+        }else if (ct === 'flp') {
+        cta.push('FLP');
         } else if (ct === 'rootdir') {
         cta.push('Containers');
         }
@@ -3844,6 +3846,7 @@
     me.callParent();
     }
 });
+
 Ext.define('PVE.form.ControllerSelector', {
     extend: 'Ext.form.FieldContainer',
     alias: ['widget.PVE.form.ControllerSelector'],
@@ -3953,7 +3956,100 @@
 
     me.callParent();
     }
-});   Ext.define('PVE.form.RealmComboBox', {
+});
+
+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();
+    }
+});
+
+
+   Ext.define('PVE.form.RealmComboBox', {
     extend: 'Ext.form.field.ComboBox',
     alias: ['widget.pveRealmComboBox'],
 
@@ -4527,7 +4623,7 @@
 
     me.data = [];
 
-    var cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir'];
+    var cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir', 'flp'];
     Ext.Array.each(cts, function(ct) {
         me.data.push([ct, PVE.Utils.format_content_types(ct)]);
     });
@@ -10146,6 +10242,142 @@
     }
 });
 
+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();
+    }
+});
+
 Ext.define('PVE.qemu.CDEdit', {
     extend: 'PVE.window.Edit',
 
@@ -10188,6 +10420,51 @@
     });
     }
 });
+
+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);
+        }
+        }
+    });
+    }
+});
+
+
 // fixme: howto avoid jslint type confusion?
 /*jslint confusion: true */
 Ext.define('PVE.qemu.HDInputPanel', {
@@ -10621,6 +10898,16 @@
         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] = {
@@ -10786,6 +11073,19 @@
                     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',
@@ -13613,6 +13913,7 @@
             data: [
             ['iso', 'ISO image'],
             ['backup', 'VZDump backup file'],
+            ['flp', 'FLP image'],
             ['vztmpl', 'OpenVZ template']
             ],
             fieldLabel: gettext('Content'),
 

About

The Proxmox community has been around for many years and offers help and support for Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.
We think our community is one of the best thanks to people like you!

Get your subscription!

The Proxmox team works very hard to make sure you are running the best software and getting stable updates and security enhancements, as well as quick enterprise support. Tens of thousands of happy customers have a Proxmox subscription. Get yours easily in our online shop.

Buy now!