Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals

entry.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2005, 2006 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: entry.c,v 1.21 2006/10/12 08:35:46 tat Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <stdlib.h>
00013 #include <unistd.h>
00014 #include <stdio.h>
00015 #include <u/libu.h>
00016 #include <klone/klone.h>
00017 #include <klone/server.h>
00018 #include <klone/os.h>
00019 #include <klone/context.h>
00020 #include <klone/utils.h>
00021 #include <klone/version.h>
00022 #include "main.h"
00023 
00024 int facility = LOG_LOCAL0;
00025 
00026 static context_t c;
00027 context_t  *ctx = &c; /* exported */
00028 
00029 #ifdef OS_WIN
00030     /* Win32 service name and description */
00031     enum { SS_NAME_BUFSZ = 64, SS_DESC_BUFSZ = 256 };
00032     static char ss_name[SS_NAME_BUFSZ] = "kloned";
00033     static char ss_desc[SS_DESC_BUFSZ] = "kloned daemon";
00034 
00035     int InstallService(); 
00036     int RemoveService();
00037 #endif
00038 
00039 static void usage()
00040 {
00041     static const char *us = 
00042 "Usage: kloned OPTIONS ARGUMENTS                                            \n"
00043 "Version: %s - Copyright (c) 2005, 2006 KoanLogic s.r.l. - All rights reserved.   \n"
00044 "\n"
00045 "    -d          turn on debugging                                          \n"
00046 "    -f file     load an external config file                               \n"
00047 "    -F          run in foreground                                          \n"
00048 "    -h          display this help                                          \n"
00049 #ifdef OS_WIN
00050 "    -i          install KLone Windows service                              \n"
00051 "    -u          remove KLone Windows service                               \n"
00052 #endif
00053 "    -V          print KLone version and exit                               \n"
00054 "\n";
00055 
00056     fprintf(stderr, us, klone_version());
00057 
00058     exit(1);
00059 }
00060 
00061 static int parse_opt(int argc, char **argv)
00062 {
00063     int ret;
00064 #ifdef OS_WIN
00065         #define CMDLINE_FORMAT "hVFdiuf:"
00066 #else
00067         #define CMDLINE_FORMAT "hVFdf:"
00068 #endif
00069 
00070     /* set defaults */
00071     ctx->daemon++;
00072 
00073     while((ret = getopt(argc, argv, CMDLINE_FORMAT)) != -1)
00074     {
00075         switch(ret)
00076         {
00077         case 'f':   /* source a config file */
00078             ctx->ext_config = u_strdup(optarg);
00079             dbg_err_if(ctx->ext_config == NULL);
00080             dbg("ext config: %s", ctx->ext_config);
00081             break;
00082 
00083         case 'd':   /* turn on debugging */
00084             ctx->debug++;
00085             break;
00086 
00087         case 'F':   /* run in foreground (not as a daemon/service) */
00088             ctx->daemon = 0;
00089             break;
00090 
00091         case 'V':   /* print version and exit */
00092             u_print_version_and_exit();
00093             break;
00094 
00095 #ifdef OS_WIN
00096         case 'i':   /* install kloned service and exit */
00097             ctx->serv_op = SERV_INSTALL;
00098             break;
00099 
00100         case 'u':   /* uninstall kloned service and exit */
00101             ctx->serv_op = SERV_REMOVE;
00102             break;
00103 
00104 #endif
00105 
00106         default:
00107         case 'h': 
00108             usage();
00109         }
00110     }
00111 
00112     ctx->narg = argc - optind;
00113     ctx->arg = argv + optind;
00114 
00115     return 0;
00116 err:
00117     return ~0;
00118 }
00119 
00120 #if defined(OS_WIN)
00121 
00122 /* install the service with the service manager. after successful installation
00123    you can run the service from ControlPanel->AdminTools->Services */
00124 int InstallService(void) 
00125 {
00126     SC_HANDLE hSCM, hService;
00127     char szModulePathname[_MAX_PATH];
00128     SERVICE_DESCRIPTION sd = { ss_desc };
00129     int rc;
00130 
00131     // Open the SCM on this machine.
00132     hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
00133 
00134     dbg_err_if(hSCM == NULL);
00135 
00136     dbg_err_if(GetModuleFileName(GetModuleHandle(NULL), szModulePathname, 
00137         _MAX_PATH) == 0 );
00138 
00139     /* add this service to the SCM's database */
00140     hService = CreateService(hSCM, ss_name, ss_name,
00141         SERVICE_CHANGE_CONFIG, SERVICE_WIN32_OWN_PROCESS, 
00142         SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
00143         szModulePathname, NULL, NULL, NULL, NULL, NULL);
00144 
00145     dbg_err_if(hService == NULL);
00146 
00147     rc = ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sd);
00148 
00149     dbg_err_if(rc == 0);
00150 
00151     /* success */
00152     MessageBox(NULL, "Service installation succeded", ss_name, MB_OK);
00153 
00154     return 0; 
00155 err:
00156     /* common error handling */
00157     warn_strerror(GetLastError());
00158     MessageBox(NULL, "Service installation error", ss_name, MB_OK);
00159     return ~0;
00160 }
00161 
00162 /* uninstall this service from the system */
00163 int RemoveService(void) 
00164 {
00165     SC_HANDLE hSCM, hService;
00166     int rc;
00167 
00168     hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
00169 
00170     dbg_err_if(hSCM == NULL);
00171 
00172     /* Open this service for DELETE access */
00173     hService = OpenService(hSCM, ss_name, DELETE);
00174 
00175     dbg_err_if(hService == NULL);
00176 
00177     /* Remove this service from the SCM's database */
00178     rc = DeleteService(hService);
00179 
00180     dbg_err_if(rc == 0);
00181 
00182     /* success */
00183     MessageBox(NULL, "Uninstall secceded", ss_name, MB_OK);
00184     return 0;
00185 err:
00186     /* common error handling */
00187     warn_strerror(GetLastError());
00188     MessageBox(NULL, "Uninstall failed", ss_name, MB_OK);
00189     return ~0;
00190 }
00191 
00192 /* this function will be called by the SCM to request an action */
00193 DWORD WINAPI HandlerEx(DWORD dwControl, DWORD dwEventType, 
00194         LPVOID lpEventData, LPVOID lpContext)
00195 {
00196     enum { DENY_ACTION = 0xff };
00197 
00198     switch(dwControl)
00199     {
00200     case SERVICE_CONTROL_INTERROGATE:
00201         dbg("SERVICE_CONTROL_INTERROGATE" );
00202         SetServiceStatus(ctx->hServiceStatus, &ctx->status);
00203         return NO_ERROR;
00204 
00205     case SERVICE_CONTROL_STOP:
00206         dbg("SERVICE_CONTROL_STOP");
00207 
00208         if(ctx->status.dwCurrentState == SERVICE_STOPPED)
00209             return NO_ERROR; /* service already stopped */
00210 
00211         /* start the stop procedure, move to stop_pending state */
00212         ctx->status.dwCheckPoint = 1;
00213         ctx->status.dwWaitHint = 2000;
00214         ctx->status.dwCurrentState = SERVICE_STOP_PENDING; 
00215         SetServiceStatus(ctx->hServiceStatus, &ctx->status);
00216 
00217         server_stop(ctx->server);
00218         return NO_ERROR;
00219 
00220     case SERVICE_CONTROL_PAUSE:
00221         dbg("SERVICE_CONTROL_PAUSE");
00222         break;
00223 
00224     case SERVICE_CONTROL_CONTINUE:
00225         dbg("SERVICE_CONTROL_CONTINUE");
00226         break;
00227 
00228     case SERVICE_CONTROL_SHUTDOWN:
00229         dbg("SERVICE_CONTROL_SHUTDOWN");
00230         break;
00231 
00232     case SERVICE_CONTROL_PARAMCHANGE:
00233         dbg("SERVICE_CONTROL_PARAMCHANGE");
00234         break;
00235 
00236     default:
00237         dbg("SERVICE_CONTROL_UNKNOWN!!!!");
00238     }
00239     if(dwControl > 127 && dwControl < 255)
00240     {
00241         /* user defined control code */
00242         dbg("SERVICE_CONTROL_USER_DEFINED");
00243     }
00244 
00245     return ERROR_CALL_NOT_IMPLEMENTED;
00246 }
00247 
00248 /* this is the main function of the service. when this function returns the
00249  * service will be terminated by the SCM */
00250 void WINAPI ServiceMain(DWORD argc, PTSTR *argv)
00251 {
00252     SERVICE_STATUS *pSt = &ctx->status;
00253 
00254     /* register the service with the ServiceControlManager */
00255     ctx->hServiceStatus = RegisterServiceCtrlHandlerEx(ss_name, HandlerEx, ctx);
00256     dbg_err_if( ctx->hServiceStatus == 0 );
00257 
00258     /* init the status struct and update the service status */
00259     ZeroMemory(pSt, sizeof(SERVICE_STATUS));
00260     /* just one service in this exe */
00261     pSt->dwServiceType = SERVICE_WIN32_OWN_PROCESS; 
00262     /* action supported by the service */
00263     pSt->dwControlsAccepted = SERVICE_ACCEPT_STOP;
00264     /* error returned while starting/stopping */
00265     pSt->dwWin32ExitCode = NO_ERROR;          
00266     /* service specific exit code */
00267     pSt->dwServiceSpecificExitCode = 0;          
00268     /* we're still initializing */
00269     pSt->dwCurrentState = SERVICE_START_PENDING;
00270     /* for progress operation */
00271     pSt->dwCheckPoint = 1;
00272     /* wait hint */
00273     pSt->dwWaitHint = 1000;
00274     /* set status */
00275     dbg_err_if(SetServiceStatus(ctx->hServiceStatus, pSt) == 0);
00276 
00277     dbg_err_if(parse_opt(argc, argv));
00278 
00279     /* load config and initialize */
00280     dbg_err_if(app_init());
00281 
00282     /* this should happen after initialization but I don't want to
00283        mess main.c with win32-only code */
00284 
00285     /* notify the end of initialization */
00286     dbg("SERVICE_RUNNING");
00287     ctx->status.dwCurrentState = SERVICE_RUNNING;
00288     ctx->status.dwCheckPoint = ctx->status.dwWaitHint = 0;    
00289     dbg_err_if(!SetServiceStatus(ctx->hServiceStatus, &ctx->status));
00290 
00291     /* run the main loop */
00292     app_run();
00293 
00294     /* let the service terminate */
00295     ctx->status.dwCurrentState = SERVICE_STOPPED;
00296     dbg_err_if(!SetServiceStatus(ctx->hServiceStatus, &ctx->status));
00297 
00298     return;
00299 
00300 err:
00301     warn_strerror(GetLastError());
00302 
00303     /* let the service terminate */
00304     ctx->status.dwCurrentState = SERVICE_STOPPED;
00305     dbg_err_if(!SetServiceStatus(ctx->hServiceStatus, &ctx->status));
00306 }
00307 
00308 int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, 
00309     LPSTR lpCmdLine, int nCmdShow)
00310 {
00311     SERVICE_TABLE_ENTRY ServiceTable[] = 
00312     {
00313         {   ss_name, ServiceMain }, 
00314         {   NULL, NULL }    /* end of list */
00315     };
00316     int rc = 0;
00317     const char *name, *desc;
00318 
00319     memset(ctx, 0, sizeof(context_t));
00320 
00321     /* parse command line parameters (and set ctx vars). NOTE: this work only 
00322        if launched by command line, for services see ServiceMain */
00323     dbg_err_if(parse_opt(__argc, __argv));
00324 
00325     if(ctx->serv_op)
00326     {
00327         /* load config and initialize */
00328         dbg_err_if(app_init());
00329 
00330         /* set up service name and description reading from the config file */
00331         name = u_config_get_subkey_value(ctx->config, "daemon.name");
00332         if(name)
00333             strncpy(ss_name, name, SS_NAME_BUFSZ);
00334 
00335         desc = u_config_get_subkey_value(ctx->config, "daemon.description");
00336         if(desc)
00337             strncpy(ss_desc, desc, SS_DESC_BUFSZ);
00338 
00339         if(ctx->serv_op == SERV_INSTALL)
00340             dbg_err_if(InstallService());
00341         else    
00342             dbg_err_if(RemoveService());
00343     } else if(ctx->daemon) {
00344         dbg("Starting in service mode...");
00345         /* StartServiceCtrlDispatcher does not return until the service 
00346            has stopped running...  */
00347         if(!StartServiceCtrlDispatcher(ServiceTable))
00348             warn_strerror(GetLastError());
00349     } else {
00350         /* load config and initialize */
00351         dbg_err_if(app_init());
00352 
00353         rc = app_run();
00354     }
00355 
00356     dbg_err_if(app_term());
00357 
00358     /* if debugging then call exit(3) because it's needed to gprof to dump 
00359        its stats file (gmon.out) */
00360     if(ctx->debug)
00361         return rc;
00362 
00363     /* don't use return because exit(3) will be called and we don't want
00364        FILE* buffers to be automatically flushed (klog_file_t will write same 
00365        lines more times, once by the parent process and N times by any child
00366        created when FILE buffer was not empty) */
00367     _exit(rc); 
00368 err:
00369     app_term();
00370 
00371     if(ctx->debug) 
00372         return rc;
00373     _exit(EXIT_FAILURE);
00374 }
00375 
00376 #elif defined(OS_UNIX)
00377 
00378 int main(int argc, char **argv)
00379 {
00380     int rc = 0;
00381 
00382     memset(ctx, 0, sizeof(context_t));
00383 
00384     /* parse command line parameters (and set ctx vars) */
00385     dbg_err_if(parse_opt(argc, argv));
00386 
00387     if(getenv("GATEWAY_INTERFACE"))
00388         ctx->cgi = 1;
00389         
00390     /* load config and initialize */
00391     warn_err_ifm(app_init(), "kloned init error (more info in the log file)");
00392 
00393     /* daemonize if not -F */
00394     if(ctx->daemon && !ctx->cgi)
00395         con_err_ifm(daemon(0, 0), "daemon error");
00396 
00397     /* jump to the main loop */
00398     rc = app_run();
00399 
00400     dbg_err_if(app_term());
00401 
00402     /* if debugging then call exit(3) because it's needed to gprof to dump 
00403        its stats file (gmon.out) */
00404     if(ctx->debug)
00405         return rc;
00406 
00407     /* don't use return because exit(3) will be called and we don't want
00408        FILE* buffers to be automatically flushed (klog_file_t will write same 
00409        lines more times, once by the parent process and N times by any child
00410        created when FILE buffer was not empty) */
00411     _exit(rc);
00412 err:
00413     app_term();
00414     if(ctx->debug)
00415         return ~0;
00416     _exit(EXIT_FAILURE);
00417 }
00418 
00419 #else
00420     #error unsupported platform
00421 #endif
00422 

←Products
© 2005-2006 - KoanLogic S.r.l. - All rights reserved