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