httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wr...@locus.apache.org
Subject cvs commit: apache-1.3/src/main http_main.c
Date Mon, 03 Jul 2000 14:50:56 GMT
wrowe       00/07/03 07:50:55

  Modified:    src/os/win32 service.h service.c
               src/main http_main.c
  Log:
    This patch for Win32 holds the console window open for up to 30 seconds
    on error until dismissed with the <ESC> key or timing out.
  
    It also traps every stderr logged message to the WinNT Application Event
    log for WinNT/2000 services.  Since Win95 services aren't, they will
    follow the first exception (holding the service console window open.)
  
      Every "Apache just pops up and goes away" and
            "Error 1067 starting service" complaint.
  
  Revision  Changes    Path
  1.9       +13 -0     apache-1.3/src/os/win32/service.h
  
  Index: service.h
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/os/win32/service.h,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- service.h	2000/06/12 00:41:23	1.8
  +++ service.h	2000/07/03 14:50:52	1.9
  @@ -3,6 +3,19 @@
   #define SERVICE_H
   
   #ifdef WIN32
  +
  +/* BIG RED WARNING: exit() is mapped to allow us to capture the exit
  + * status.  This header must only be included from modules linked into
  + * the ApacheCore.dll - since it's a horrible behavior to exit() from
  + * any module outside the main() block, and we -will- assume it's a
  + * fatal error.  No dynamically linked module will ever be able to find
  + * the real_exit_code, and _will_ GP fault if it tries this macro.
  + */
  +
  +#define exit(status) ((exit)(real_exit_code ? (real_exit_code = (status)) : (status)))
  +extern int real_exit_code;
  +void hold_console_open_on_error(void);
  +
   int service_main(int (*main_fn)(int, char **), int argc, char **argv);
   int service95_main(int (*main_fn)(int, char **), int argc, char **argv,
   		   char *display_name);
  
  
  
  1.24      +202 -8    apache-1.3/src/os/win32/service.c
  
  Index: service.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/os/win32/service.c,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- service.c	2000/06/16 18:31:13	1.23
  +++ service.c	2000/07/03 14:50:52	1.24
  @@ -41,6 +41,71 @@
   static int ap_stop_service(SC_HANDLE);
   static int ap_restart_service(SC_HANDLE);
   
  +/* exit() for Win32 is macro mapped (horrible, we agree) that allows us 
  + * to catch the non-zero conditions and inform the console process that
  + * the application died, and hang on to the console a bit longer.
  + *
  + * The macro only maps for http_main.c and other sources that include
  + * the service.h header, so we best assume it's an error to exit from
  + * _any_ other module.
  + *
  + * If real_exit_code is reset to 0, it will not be set or trigger this
  + * behavior on exit.  All service and child processes are expected to
  + * reset this flag to zero to avoid undesireable side effects.
  + */
  +int real_exit_code = 1;
  +
  +void hold_console_open_on_error(void)
  +{
  +    HANDLE hConIn;
  +    HANDLE hConErr;
  +    DWORD result;
  +    time_t start;
  +    time_t remains;
  +    char *msg = "Note the errors or messages above, "
  +                "and press the <ESC> key to exit.  ";
  +    CONSOLE_SCREEN_BUFFER_INFO coninfo;
  +    INPUT_RECORD in;
  +    char count[16];
  +    
  +    if (!real_exit_code)
  +        return;
  +    hConIn = GetStdHandle(STD_INPUT_HANDLE);
  +    hConErr = GetStdHandle(STD_ERROR_HANDLE);
  +    if ((hConIn == INVALID_HANDLE_VALUE) || (hConErr == INVALID_HANDLE_VALUE))
  +        return;
  +    if (!WriteConsole(hConErr, msg, strlen(msg), &result, NULL) || !result)
  +        return;
  +    if (!GetConsoleScreenBufferInfo(hConErr, &coninfo))
  +        return;
  +    if (!SetConsoleMode(hConIn, ENABLE_MOUSE_INPUT | 0x80))
  +        return;
  +        
  +    start = time(NULL);
  +    do
  +    {
  +        while (PeekConsoleInput(hConIn, &in, 1, &result) && result)
  +        {
  +            if (!ReadConsoleInput(hConIn, &in, 1, &result) || !result)
  +                return;
  +            if ((in.EventType == KEY_EVENT) && in.Event.KeyEvent.bKeyDown 
  +                    && (in.Event.KeyEvent.uChar.AsciiChar == 27))
  +                return;
  +            if (in.EventType == MOUSE_EVENT 
  +                    && (in.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))
  +                return;
  +        }
  +        remains = ((start + 30) - time(NULL)); 
  +        sprintf (count, "%d...", remains);
  +        if (!SetConsoleCursorPosition(hConErr, coninfo.dwCursorPosition))
  +            return;
  +        if (!WriteConsole(hConErr, count, strlen(count), &result, NULL) 
  +                || !result)
  +            return;
  +    }
  +    while ((remains > 0) && WaitForSingleObject(hConIn, 1000) != WAIT_FAILED);
  +}
  +
   int service_main(int (*main_fn)(int, char **), int argc, char **argv )
   {
       SERVICE_TABLE_ENTRY dispatchTable[] =
  @@ -49,6 +114,9 @@
           { NULL, NULL }
       };
   
  +    /* Prevent holding open the (nonexistant) console */
  +    real_exit_code = 0;
  +
       globdat.main_fn = main_fn;
       globdat.stop_event = create_event(0, 0, "apache-signal");
       globdat.connected = 1;
  @@ -171,7 +239,7 @@
       /* Windows 95/98 */
       char *service_name;
       HANDLE thread;
  -    
  +
       /* Remove spaces from display name to create service name */
       service_name = strdup(display_name);
       ap_remove_spaces(service_name, display_name);
  @@ -191,12 +259,16 @@
       if (!RegisterServiceProcess((DWORD)NULL, 1))
           return -1;
   
  +    /* Prevent holding open the (nonexistant) console */
  +    real_exit_code = 0;
  +
       /* Hide the console */
       FreeConsole();
   
       thread = CreateThread(NULL, 0, WatchWindow, (LPVOID) service_name, 0, 
   			  &monitor_thread_id);
  -    CloseHandle(thread);
  +    if (thread)
  +        CloseHandle(thread);
   
       atexit(stop_service_monitor);
   
  @@ -215,11 +287,87 @@
       chdir(buf);
   }
   
  +long __stdcall service_stderr_thread(LPVOID hPipe)
  +{
  +    HANDLE hPipeRead = (HANDLE) hPipe;
  +    HANDLE hEventSource;
  +    char errbuf[256];
  +    char *errmsg = errbuf;
  +    char *errarg[9];
  +    DWORD errlen = 0;
  +    DWORD errres;
  +    HKEY hk;
  +    
  +    errarg[0] = "The Apache service named";
  +    errarg[1] = ap_server_argv0;
  +    errarg[2] = "reported the following error:\r\n>>>";
  +    errarg[3] = errmsg;
  +    errarg[4] = "<<<\r\n before the error.log file could be opened.\r\n";
  +    errarg[5] = "More information may be available in the error.log file.";
  +    errarg[6] = NULL;
  +    errarg[7] = NULL;
  +    errarg[8] = NULL;
  +    
  +    /* What are we going to do in here, bail on the user?  not. */
  +    if (!RegCreateKey(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services"
  +                      "\\EventLog\\Application\\Apache Service", &hk)) 
  +    {
  +        /* The stock message file */
  +        char *netmsgkey = "%SystemRoot%\\System32\\netmsg.dll";
  +        DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | 
  +                       EVENTLOG_INFORMATION_TYPE; 
  + 
  +        RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ,
  +                          (LPBYTE) netmsgkey, strlen(netmsgkey) + 1);
  +        
  +        RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD,
  +                          (LPBYTE) &dwData, sizeof(dwData));
  +        RegCloseKey(hk);
  +    }
  +
  +    hEventSource = RegisterEventSource(NULL, "Apache Service");
  +
  +    while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1))
  +    {
  +        if ((errmsg > errbuf) || !isspace(*errmsg))
  +        {
  +            ++errlen;
  +            ++errmsg;
  +            if ((*(errmsg - 1) == '\n') || (errlen == sizeof(errbuf) - 1))
  +            {
  +                while (errlen && isspace(errbuf[errlen - 1]))
  +                    --errlen;
  +                errbuf[errlen] = '\0';
  +
  +                /* Generic message: '%1 %2 %3 %4 %5 %6 %7 %8 %9'
  +                 * The event code in netmsg.dll is 3299
  +                 */
  +                ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 
  +                            3299, NULL, 9, 0, errarg, NULL);
  +                errmsg = errbuf;
  +                errlen = 0;
  +            }
  +        }
  +    }
  +
  +    CloseHandle(hPipeRead);
  +    return 0;
  +}
  +
   void __stdcall service_main_fn(DWORD argc, LPTSTR *argv)
   {
  +    HANDLE hCurrentProcess;
  +    HANDLE hPipeRead = NULL;
  +    HANDLE hPipeWrite = NULL;
  +    HANDLE hPipeReadDup;
  +    HANDLE thread;
  +    DWORD  threadid;
  +    SECURITY_ATTRIBUTES sa = {0};  
  +    
       ap_server_argv0 = globdat.name = argv[0];
  -
  -    if(!(globdat.hServiceStatus = RegisterServiceCtrlHandler( globdat.name, service_ctrl)))
  +    
  +    if(!(globdat.hServiceStatus = RegisterServiceCtrlHandler(globdat.name, 
  +                                                             service_ctrl)))
       {
           ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
           "Failure registering service handler");
  @@ -231,11 +379,54 @@
           NO_ERROR,              // exit code
           3000);                 // wait hint
   
  +    /* Create a pipe to send stderr messages to the system error log */
  +    hCurrentProcess = GetCurrentProcess();
  +    if (CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) 
  +    {
  +        if (DuplicateHandle(hCurrentProcess, hPipeRead, hCurrentProcess,
  +                            &hPipeReadDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
  +        {
  +            CloseHandle(hPipeRead);
  +            hPipeRead = hPipeReadDup;
  +            thread = CreateThread(NULL, 0, service_stderr_thread, 
  +                                  (LPVOID) hPipeRead, 0, &threadid);
  +            if (thread)
  +            {
  +                int fh;
  +                FILE *fl;
  +                CloseHandle(thread);
  +            	fflush(stderr);
  +		SetStdHandle(STD_ERROR_HANDLE, hPipeWrite);
  +				
  +                fh = _open_osfhandle((long) STD_ERROR_HANDLE, 
  +                                     _O_WRONLY | _O_BINARY);
  +                dup2(fh, STDERR_FILENO);
  +                fl = _fdopen(STDERR_FILENO, "wcb");
  +                memcpy(stderr, fl, sizeof(FILE));
  +            }
  +            else
  +            {
  +                CloseHandle(hPipeRead);
  +                CloseHandle(hPipeWrite);
  +                hPipeWrite = NULL;
  +            }            
  +        }
  +        else
  +        {
  +            CloseHandle(hPipeRead);
  +            CloseHandle(hPipeWrite);
  +            hPipeWrite = NULL;
  +        }            
  +    }
  +
       service_cd();
       if( service_init() ) 
           /* Arguments are ok except for \! */
           globdat.exit_status = (*globdat.main_fn)( argc, argv );
  -    
  +
  +    if (hPipeWrite)
  +        CloseHandle(hPipeWrite);
  +
       ReportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 0);
   
       return;
  @@ -722,7 +913,8 @@
                    * will simply fall through and *THIS* process will fade into an
                    * invisible 'service' process, detaching from the user's console.
                    * We need to change the restart signal to "start", however,
  -                 * if the service was not -yet- running.
  +                 * if the service was not -yet- running, and we do return FALSE
  +                 * to assure main() that we haven't done anything yet.
                    */
                   if (action == restart) 
                   {
  @@ -731,7 +923,6 @@
                       else
                           ap_start_restart(1);
                   }
  -                success = TRUE;
               }
           }
   
  @@ -811,6 +1002,7 @@
       {
           case CTRL_C_EVENT:
           case CTRL_BREAK_EVENT:
  +            real_exit_code = 0;
               fprintf(stderr, "Apache server interrupted...\n");
               /* for Interrupt signals, shut down the server.
                * Tell the system we have dealt with the signal
  @@ -827,6 +1019,7 @@
                * after a reasonable time to tell the system
                * that we have already tried to shut down.
                */
  +            real_exit_code = 0;
               fprintf(stderr, "Apache server shutdown initiated...\n");
               ap_start_shutdown();
               Sleep(30000);
  @@ -884,7 +1077,8 @@
           HANDLE thread;
           thread = CreateThread(NULL, 0, WatchWindow, NULL, 0, 
                                 &monitor_thread_id);
  -        CloseHandle(thread);
  +        if (thread)
  +            CloseHandle(thread);
       }
   
       atexit(stop_console_monitor);
  
  
  
  1.504     +44 -9     apache-1.3/src/main/http_main.c
  
  Index: http_main.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/main/http_main.c,v
  retrieving revision 1.503
  retrieving revision 1.504
  diff -u -r1.503 -r1.504
  --- http_main.c	2000/06/16 18:31:04	1.503
  +++ http_main.c	2000/07/03 14:50:54	1.504
  @@ -5677,7 +5677,7 @@
           
           ap_destroy_pool(pchild);
           cleanup_scoreboard();
  -        exit(0);
  +        exit(1);
       }
       
       set_signals();
  @@ -5879,7 +5879,7 @@
   
   	ap_destroy_pool(pchild);
   	cleanup_scoreboard();
  -	exit(0);
  +	exit(1);
       }
       if (rv == WAIT_OBJECT_0 + 1) {
   	/* exit event signalled - exit now */
  @@ -5904,7 +5904,7 @@
   
   	ap_destroy_pool(pchild);
   	cleanup_scoreboard();
  -	exit(0);
  +	exit(1);
       }
       set_signals();
   
  @@ -6118,6 +6118,8 @@
       DWORD BytesWritten;
       HANDLE hPipeRead = NULL;
       HANDLE hPipeWrite = NULL;
  +    HANDLE hPipeWriteDup;
  +    HANDLE hCurrentProcess;
       SECURITY_ATTRIBUTES sa = {0};  
   
       sa.nLength = sizeof(sa);
  @@ -6166,6 +6168,14 @@
           return -1;
       }
   
  +    hCurrentProcess = GetCurrentProcess();
  +    if (DuplicateHandle(hCurrentProcess, hPipeWrite, hCurrentProcess,
  +                        &hPipeWriteDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
  +    {
  +        CloseHandle(hPipeWrite);
  +        hPipeWrite = hPipeWriteDup;
  +    }
  +
       /* Give the read in of the pipe (hPipeRead) to the child as stdin. The 
        * parent will write the socket data to the child on this pipe.
        */
  @@ -6626,6 +6636,9 @@
               clean_parent_exit(0);
           }
       }
  +
  +    /* This behavior is voided by setting real_exit_code to 0 */
  +    atexit(hold_console_open_on_error);
   #endif
   
   #ifdef NETWARE
  @@ -6679,6 +6692,8 @@
   	    break;
   #ifdef WIN32
   	case 'Z':
  +            /* Prevent holding open the (nonexistant) console */
  +            real_exit_code = 0;
   	    exit_event = open_event(optarg);
   	    APD2("child: opened process event %s", optarg);
   	    cp = strchr(optarg, '_');
  @@ -6735,20 +6750,36 @@
   	    ap_set_version();
   	    printf("Server version: %s\n", ap_get_server_version());
   	    printf("Server built:   %s\n", ap_get_server_built());
  +#ifdef NETWARE
               clean_parent_exit(0);
  +#else
  +            clean_parent_exit(1);
  +#endif
   
  -	case 'V':
  +        case 'V':
   	    ap_set_version();
   	    show_compile_settings();
  +#ifdef NETWARE
               clean_parent_exit(0);
  +#else
  +            clean_parent_exit(1);
  +#endif
   
   	case 'l':
   	    ap_show_modules();
  +#ifdef NETWARE
               clean_parent_exit(0);
  +#else
  +            clean_parent_exit(1);
  +#endif
   
   	case 'L':
   	    ap_show_directives();
  +#ifdef NETWARE
               clean_parent_exit(0);
  +#else
  +            clean_parent_exit(1);
  +#endif
   
   	case 'X':
   	    ++one_process;	/* Weird debugging mode. */
  @@ -6785,14 +6816,14 @@
           if (install > 0) {
               ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, NULL,
                            "Service \"%s\" is already installed!", service_name);
  -            clean_parent_exit(0);
  +            clean_parent_exit(1);
           }
       }
       else if (service_name && (install <= 0))
       {
           ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, NULL,
                        "Service \"%s\" is not installed!", service_name);
  -        clean_parent_exit(0);
  +        clean_parent_exit(1);
       }
   #endif
   
  @@ -6851,16 +6882,20 @@
   
       if (service_name && !conf_specified) {
           printf("Unknown service: %s\n", service_name);
  -        clean_parent_exit(0);
  +        clean_parent_exit(1);
       }
   
       /* All NT signals, and all but the 9x start signal are handled entirely.
        * Die if we failed, are on NT, or are not "start"ing the service
        */
       if (service_name && signal_to_send) {
  -        if (!send_signal_to_service(service_name, signal_to_send)
  -                || isWindowsNT() || strcasecmp(signal_to_send, "start"))
  +        if (send_signal_to_service(service_name, signal_to_send))
               clean_parent_exit(0);
  +        if (isWindowsNT() || strcasecmp(signal_to_send, "start"))
  +            clean_parent_exit(1);
  +        /* Still here?  Then we are hanging around to detach the console 
  +         * and use this process as the Windows 9x service.
  +         */
       }
   #else /* ndef WIN32 */
       server_conf = ap_read_config(pconf, ptrans, ap_server_confname);
  
  
  

Mime
View raw message