If anyone cares, I've updated my on-quit-0.21 patch to cleanly apply to
qemu 0.7.1 (to be precise the 2005-07-23 nightly snapshot of 0.7.1).

Instructions and history below. Feedback still welcome.

Struan

On Sat, 7 May 2005, Struan Bartlett wrote:

> Having had the APM bios fixed in the 0.7 Qemu release, which allows
> Windows 2000 to correctly signal Qemu when it wants to shutdown the VM,
> I've updated my '-on-quit' patch - which prevented the VM from being
> crudely shut down by accidentally pressing Ctrl-C or closing the VM
> window - to remove the nasty i386-specific "halt-instruction-detection"
> code and provide what I hope you will agree is a cleaner replacement.
>
> The new patch instead relies on APM/SDL/Cocoa/Cuda each specifying
> whether the shutdown request originated from the hardware or from the
> user. In the case of user request, Qemu's behaviour will depend on the
> command line option specified: 1. '-on-quit ignore' means ignore the
> Ctrl-C; 2. '-on-quit suspend' means suspend the VM. In the case of a
> hardware shutdown, the VM will shut down normally (but if '-on-quit
> suspend' was selected it will delete the named suspend file first).
>
> The patch features extra options '-on-quit ask' and '-on-quit
> <filepath>' which both cause Qemu to run a script to ask the user
> whether they want to resume, suspend or power off the VM. For non-WIN32
> platforms, this is easily implemented it using a script that the
> xmessage command i.e.:
>
> #!/bin/sh
>
> exec /usr/bin/X11/xmessage -center -timeout 10 -buttons
> 'Resume:0,Suspend:1,Power Off:2' 'Do you want to resume, suspend, or
> power off this virtual machine?'
>
> The '-on-quit ask' option assumes a default script filename
> "on_quit_ask", assumed to be in the CONFIG_QEMU_SHAREDIR directory (i.e.
> usually /usr/local/share/qemu).
>
> Example command (Linux) which should correctly buffer naive users from
> accidental VM shutdown and suspend file overwriting: it resumes from
> suspended.qemu file if it exists; asks user whether to resume, power off
> or suspend on CTRL-C or window close; suspend saves to the same file;
> power off deleted the suspend file.
>
> qemu -hda win2k.raw -m 64 -monitor null -loadvm suspended.qemu -on-quit ask
>
> Feedback welcome!
>
> Struan
>
> Struan Bartlett wrote:
>
> > Hi,
> >
> > I've attached a patch against the 2005-03-26 snapshot that implements
> > two '-on-quit' options for the emulator window: ignore-unless-halted
> > and suspend-unless-halted, that aim to make it safe to allow naive
> > users to (try to) close the VM window by trapping requests to shutdown
> > and either ignoring them or forcing a save of the VM state before
> > obeying them.
> >
> > Caveat: I'll come clean straight away that the patch is implemented
> > using a nasty TARGET_i386-specific hack that detects whether the guest
> > operating system has permanently halted by looking to see if the last
> > instruction executed was 0xF4 and, if so, whether the IF flag is
> > cleared. Saying that, this system appears to work reasonably well on
> > my Pentium host running a Windows 2000 guest, but I have not tested it
> > on any other systems.
> >
> > Usage:
> >
> > 1. If you provide naive users with a variation on the following
> > command line, then you can let your naive users (try to) close the VM
> > window as much as they like. Unless the guest has permanently halted,
> > attempts to close the VM window should save the VM state to
> > 'suspended.qemu' in the current working directory before qemu exits.
> > The same command line will restart the VM where it left off. Then,
> > once the guest has permanently halted, qemu will delete the
> > suspended.qemu file so that the next launch of qemu will boot afresh:
> >
> > qemu -hda win2k.raw -m 64 -monitor null -loadvm suspended.qemu
> > -on-quit suspend-unless-halted
> >
> > 2. Alternatively, the following command will make qemu ignore the
> > user's request to close the emulator window unless the guest has
> > already permanently halted:
> >
> > qemu -hda win2k.raw -m 64 -monitor null -on-quit ignore-unless-halted
> >
> > 3. If you combine this with a test of whether qemu is already running,
> > then it should be safe to let naive users try to both launch and to
> > close qemu as much as they like. e.g.
> >
> > killall -0 qemu 2>/dev/null; if [ $? == 1 ]; then qemu -hda win2k.raw
> > -m 64 -monitor null -loadvm suspended.qemu -on-quit
> > suspend-unless-halted; fi &
> >
> > 4. Finally, if your leave out the -on-quit option altogether, then
> > qemu's behaviour should remain completely unchanged.
> >
> > I hope this is useful for some i386/W2K users out there. Any
> > constructive criticism appreciated. If you know how I could improve
> > permanent halt detection (that doesn't require in-depth knowledge of
> > APM or ACPI) then please let me know.
> >
> > Struan
> >
> > Struan Bartlett wrote:
> >
> >> Ryan Rempel wrote:
> >>
> >>>On Mon, Nov 29, 2004 at 21:46:54 +0100, Lennert Buytenhek wrote
> >>>
> >>>
> >>>>On Mon, Nov 29, 2004 at 08:43:56PM +0000, Richard Neill wrote:
> >>>>
> >>>>
> >>>>>A thought that occurred to me. If one is running a virtual machine (eg
> >>>>>copy of WinXP), then simply closing the qemu window is a really bad
> >>>>>idea, since it will effectively crash the guest.
> >>>>>
> >>>>>
> >>>>Related thought -- it would be way cool if we could make killing qemu
> >>>>do exactly happens when you press the power button on an ACPI-capable
> >>>>machine with any recent OS on it (auto shutdown.)
> >>>>
> >>>>
> >>>I was wondering if anyone has followed up on this suggestion. I'm
> >>>putting together a Qemu-based setup for some relatively naive users,
> >>>and ideally I'd like to be able to deal with this in a reasonable
> >>>elegant way (the ACPI hook sounds very elegant indeed).
> >>>
> >>>Alternatively, how do people deal with the problem of naive users who
> >>>might just close the Qemu window without shutting down the guest
> >>>properly? I'm working in a KDE environment -- perhaps there is a way
> >>>in KDE to prevent the close button from appearing? But that wouldn't
> >>>catch every case either (for instance, if the user were to shut down
> >>>the host).
> >>>
> >> This sounds like a good idea. An alternative solution, that might be
> >> more straightforward to implement if Qemu doesn't implement ACPI yet,
> >> would be for the kill signal to simply cause Qemu to do the
> >> equivalent of entering 'stop' and 'savevm <somefilepath>' into the
> >> monitor.
> >>
diff -rbw -u qemu-snapshot-2005-07-25_23/cocoa.m 
qemu-snapshot-2005-07-25_23-on-quit/cocoa.m
--- qemu-snapshot-2005-07-25_23/cocoa.m 2005-04-07 22:36:50.000000000 +0200
+++ qemu-snapshot-2005-07-25_23-on-quit/cocoa.m 2005-07-26 23:58:44.797315738 
+0200
@@ -444,7 +444,7 @@
 - (void)applicationWillTerminate:(NSNotification *)aNotification
 {
     printf("Application will terminate\n");
-    qemu_system_shutdown_request();
+    qemu_system_shutdown_request(1);
     /* In order to avoid a crash */
     exit(0);
 }
diff -rbw -u qemu-snapshot-2005-07-25_23/hw/cuda.c 
qemu-snapshot-2005-07-25_23-on-quit/hw/cuda.c
--- qemu-snapshot-2005-07-25_23/hw/cuda.c       2005-07-23 16:01:47.000000000 
+0200
+++ qemu-snapshot-2005-07-25_23-on-quit/hw/cuda.c       2005-07-26 
23:58:45.025293898 +0200
@@ -557,7 +557,7 @@
         obuf[0] = CUDA_PACKET;
         obuf[1] = 0;
         cuda_send_packet_to_host(s, obuf, 2);
-       qemu_system_shutdown_request();
+       qemu_system_shutdown_request(1);
        break;
     default:
         break;
diff -rbw -u qemu-snapshot-2005-07-25_23/hw/pc.c 
qemu-snapshot-2005-07-25_23-on-quit/hw/pc.c
--- qemu-snapshot-2005-07-25_23/hw/pc.c 2005-07-23 21:05:37.000000000 +0200
+++ qemu-snapshot-2005-07-25_23-on-quit/hw/pc.c 2005-07-26 23:58:45.120284798 
+0200
@@ -323,7 +323,7 @@
             shutdown_index++;
             if (shutdown_index == 8) {
                 shutdown_index = 0;
-                qemu_system_shutdown_request();
+                qemu_system_shutdown_request(-1);
             }
         } else {
             shutdown_index = 0;
diff -rbw -u qemu-snapshot-2005-07-25_23/sdl.c 
qemu-snapshot-2005-07-25_23-on-quit/sdl.c
--- qemu-snapshot-2005-07-25_23/sdl.c   2005-07-23 19:54:50.000000000 +0200
+++ qemu-snapshot-2005-07-25_23-on-quit/sdl.c   2005-07-26 23:58:45.214275794 
+0200
@@ -413,7 +413,7 @@
                 sdl_process_key(&ev->key);
             break;
         case SDL_QUIT:
-            qemu_system_shutdown_request();
+              qemu_system_shutdown_request(1);
             break;
         case SDL_MOUSEMOTION:
             if (gui_grab) {
diff -rbw -u qemu-snapshot-2005-07-25_23/vl.c 
qemu-snapshot-2005-07-25_23-on-quit/vl.c
--- qemu-snapshot-2005-07-25_23/vl.c    2005-07-24 20:44:55.000000000 +0200
+++ qemu-snapshot-2005-07-25_23-on-quit/vl.c    2005-07-26 23:59:56.408455447 
+0200
@@ -144,6 +144,11 @@
 #endif
 int graphic_depth = 15;
 int full_screen = 0;
+
+#define ON_QUIT_ASK_FILENAME "on_quit_ask"
+int on_quit = 0;
+const char * on_quit_filepath = NULL;
+
 TextConsole *vga_console;
 CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
@@ -2633,9 +2638,27 @@
     cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
 }
 
-void qemu_system_shutdown_request(void)
+void qemu_system_shutdown_request(int s)
 {
-    shutdown_requested = 1;
+
+    if (s == 1 && on_quit == 3) { // User power-off request and Popup message 
setting
+        int r,c;
+       
+        if( on_quit_filepath ) r = system(on_quit_filepath);
+        else {
+            char buf[1024];
+            snprintf(buf, sizeof(buf), "%s/%s", CONFIG_QEMU_SHAREDIR, 
ON_QUIT_ASK_FILENAME);
+            r = system(buf);
+        }
+        c = WEXITSTATUS(r);
+      
+        if(c == 0) return;
+        if(c == 2) s = -1; // Simulate an APM power-off request
+        // else if r == -1, there was an error; if c == 1, then suspend;
+        // Either way, we suspend, for safety
+    }
+
+    shutdown_requested = s;
     cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
 }
 
@@ -2759,9 +2782,12 @@
         if (vm_running) {
             ret = cpu_exec(env);
             if (shutdown_requested) {
+                if (on_quit == 0 || on_quit == 2 || on_quit == 3 || (on_quit 
== 1 && shutdown_requested == -1)) {
                 ret = EXCP_INTERRUPT;
                 break;
             }
+            shutdown_requested = 0;
+            }
             if (reset_requested) {
                 reset_requested = 0;
                 qemu_system_reset();
@@ -2864,6 +2890,9 @@
            "-std-vga        simulate a standard VGA card with VESA Bochs 
Extensions\n"
            "                (default is CL-GD5446 PCI VGA)\n"
 #endif
+           "-on-quit        [ignore|suspend|ask|<script filepath>]\n"
+           "                select the behaviour when the emulator window is 
asked to quit\n"
+           "                (default is none)\n"
            "-loadvm file    start right away with a saved state (loadvm in 
monitor)\n"
            "\n"
            "During emulation, the following keys are useful:\n"
@@ -2947,6 +2976,8 @@
     QEMU_OPTION_pidfile,
     QEMU_OPTION_no_kqemu,
     QEMU_OPTION_win2k_hack,
+    QEMU_OPTION_on_quit,
+    
 };
 
 typedef struct QEMUOption {
@@ -3017,6 +3048,7 @@
     { "full-screen", 0, QEMU_OPTION_full_screen },
     { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
     { "win2k-hack", 0, QEMU_OPTION_win2k_hack },
+    { "on-quit", HAS_ARG, QEMU_OPTION_on_quit },
     
     /* temporary options */
     { "pci", 0, QEMU_OPTION_pci },
@@ -3518,6 +3550,18 @@
                 kqemu_allowed = 0;
                 break;
 #endif
+            case QEMU_OPTION_on_quit:
+                if(!strncmp(optarg, "ignore",6)) {
+                    on_quit = 1;
+                }
+                else if(!strncmp(optarg, "suspend",7)) {
+                    on_quit = 2;
+                }
+                else {
+                    on_quit = 3;
+                    if(strcmp(optarg, "ask")) on_quit_filepath = optarg;
+                }
+                break;
             }
         }
     }
@@ -3818,6 +3862,20 @@
         }
     }
     main_loop();
+
+    if (on_quit == 2 || on_quit == 3) {
+        char *f = "suspended.qemu";
+        if (shutdown_requested == -1) { // APM-request to shutdown
+
+        fprintf(stderr, "VM is halted: removing suspend file %s\n",f);
+        unlink(f);
+        }
+        else { // User-request to shutdown
+            fprintf(stderr, "Autosaving VM to file %s\n",f);
+            qemu_savevm(f);
+        }
+    }
+   
     quit_timers();
     return 0;
 }
diff -rbw -u qemu-snapshot-2005-07-25_23/vl.h 
qemu-snapshot-2005-07-25_23-on-quit/vl.h
--- qemu-snapshot-2005-07-25_23/vl.h    2005-07-23 21:05:37.000000000 +0200
+++ qemu-snapshot-2005-07-25_23-on-quit/vl.h    2005-07-27 00:00:35.382721743 
+0200
@@ -109,7 +109,7 @@
 
 void qemu_register_reset(QEMUResetHandler *func, void *opaque);
 void qemu_system_reset_request(void);
-void qemu_system_shutdown_request(void);
+void qemu_system_shutdown_request(int);
 void qemu_system_powerdown_request(void);
 #if !defined(TARGET_SPARC)
 // Please implement a power failure function to signal the OS
_______________________________________________
Qemu-devel mailing list
Qemu-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/qemu-devel

Reply via email to