00001
00002
00003
00004
00005
00006
00007
00008
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/server.h>
00017 #include <klone/os.h>
00018 #include <klone/context.h>
00019 #include <klone/utils.h>
00020 #include <klone/version.h>
00021 #include "main.h"
00022
00023 int facility = LOG_LOCAL0;
00024
00025 static context_t c;
00026 context_t *ctx = &c;
00027
00028 #ifdef OS_WIN
00029
00030 enum { SS_NAME_BUFSZ = 64, SS_DESC_BUFSZ = 256 };
00031 static char ss_name[SS_NAME_BUFSZ] = "kloned";
00032 static char ss_desc[SS_DESC_BUFSZ] = "kloned daemon";
00033
00034 int InstallService();
00035 int RemoveService();
00036 #endif
00037
00038 static void usage()
00039 {
00040 static const char *us =
00041 "Usage: kloned OPTIONS ARGUMENTS \n"
00042 "Version: %s - Copyright (c) 2005, 2006, 2007 KoanLogic s.r.l.\n"
00043 "All rights reserved.\n"
00044 "\n"
00045 " -d turn on debugging (forces iterative mode) \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
00071 ctx->daemon++;
00072
00073 while((ret = getopt(argc, argv, CMDLINE_FORMAT)) != -1)
00074 {
00075 switch(ret)
00076 {
00077 case 'f':
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':
00084 ctx->debug++;
00085 break;
00086
00087 case 'F':
00088 ctx->daemon = 0;
00089 break;
00090
00091 case 'V':
00092 u_print_version_and_exit();
00093 break;
00094
00095 #ifdef OS_WIN
00096 case 'i':
00097 ctx->serv_op = SERV_INSTALL;
00098 break;
00099
00100 case 'u':
00101 ctx->serv_op = SERV_REMOVE;
00102 break;
00103 #endif
00104
00105 default:
00106 case 'h':
00107 usage();
00108 }
00109 }
00110
00111 ctx->narg = argc - optind;
00112 ctx->arg = argv + optind;
00113
00114 return 0;
00115 err:
00116 return ~0;
00117 }
00118
00119 #if defined(OS_WIN)
00120
00121
00122
00123 int InstallService(void)
00124 {
00125 SC_HANDLE hSCM, hService;
00126 char szModulePathname[_MAX_PATH];
00127 SERVICE_DESCRIPTION sd = { ss_desc };
00128 int rc;
00129
00130
00131 hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
00132
00133 dbg_err_if(hSCM == NULL);
00134
00135 dbg_err_if(GetModuleFileName(GetModuleHandle(NULL), szModulePathname,
00136 _MAX_PATH) == 0 );
00137
00138
00139 hService = CreateService(hSCM, ss_name, ss_name,
00140 SERVICE_CHANGE_CONFIG, SERVICE_WIN32_OWN_PROCESS,
00141 SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
00142 szModulePathname, NULL, NULL, NULL, NULL, NULL);
00143
00144 dbg_err_if(hService == NULL);
00145
00146 rc = ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sd);
00147
00148 dbg_err_if(rc == 0);
00149
00150
00151 MessageBox(NULL, "Service installation succeded", ss_name, MB_OK);
00152
00153 return 0;
00154 err:
00155
00156 warn_strerror(GetLastError());
00157 MessageBox(NULL, "Service installation error", ss_name, MB_OK);
00158 return ~0;
00159 }
00160
00161
00162 int RemoveService(void)
00163 {
00164 SC_HANDLE hSCM, hService;
00165 int rc;
00166
00167 hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
00168
00169 dbg_err_if(hSCM == NULL);
00170
00171
00172 hService = OpenService(hSCM, ss_name, DELETE);
00173
00174 dbg_err_if(hService == NULL);
00175
00176
00177 rc = DeleteService(hService);
00178
00179 dbg_err_if(rc == 0);
00180
00181
00182 MessageBox(NULL, "Uninstall secceded", ss_name, MB_OK);
00183 return 0;
00184 err:
00185
00186 warn_strerror(GetLastError());
00187 MessageBox(NULL, "Uninstall failed", ss_name, MB_OK);
00188 return ~0;
00189 }
00190
00191
00192 DWORD WINAPI HandlerEx(DWORD dwControl, DWORD dwEventType,
00193 LPVOID lpEventData, LPVOID lpContext)
00194 {
00195 enum { DENY_ACTION = 0xff };
00196
00197 switch(dwControl)
00198 {
00199 case SERVICE_CONTROL_INTERROGATE:
00200 dbg("SERVICE_CONTROL_INTERROGATE" );
00201 SetServiceStatus(ctx->hServiceStatus, &ctx->status);
00202 return NO_ERROR;
00203
00204 case SERVICE_CONTROL_STOP:
00205 dbg("SERVICE_CONTROL_STOP");
00206
00207 if(ctx->status.dwCurrentState == SERVICE_STOPPED)
00208 return NO_ERROR;
00209
00210
00211 ctx->status.dwCheckPoint = 1;
00212 ctx->status.dwWaitHint = 2000;
00213 ctx->status.dwCurrentState = SERVICE_STOP_PENDING;
00214 SetServiceStatus(ctx->hServiceStatus, &ctx->status);
00215
00216 server_stop(ctx->server);
00217 return NO_ERROR;
00218
00219 case SERVICE_CONTROL_PAUSE:
00220 dbg("SERVICE_CONTROL_PAUSE");
00221 break;
00222
00223 case SERVICE_CONTROL_CONTINUE:
00224 dbg("SERVICE_CONTROL_CONTINUE");
00225 break;
00226
00227 case SERVICE_CONTROL_SHUTDOWN:
00228 dbg("SERVICE_CONTROL_SHUTDOWN");
00229 break;
00230
00231 case SERVICE_CONTROL_PARAMCHANGE:
00232 dbg("SERVICE_CONTROL_PARAMCHANGE");
00233 break;
00234
00235 default:
00236 dbg("SERVICE_CONTROL_UNKNOWN!!!!");
00237 }
00238 if(dwControl > 127 && dwControl < 255)
00239 {
00240
00241 dbg("SERVICE_CONTROL_USER_DEFINED");
00242 }
00243
00244 return ERROR_CALL_NOT_IMPLEMENTED;
00245 }
00246
00247
00248
00249 void WINAPI ServiceMain(DWORD argc, PTSTR *argv)
00250 {
00251 SERVICE_STATUS *pSt = &ctx->status;
00252
00253
00254 ctx->hServiceStatus = RegisterServiceCtrlHandlerEx(ss_name, HandlerEx, ctx);
00255 dbg_err_if( ctx->hServiceStatus == 0 );
00256
00257
00258 ZeroMemory(pSt, sizeof(SERVICE_STATUS));
00259
00260 pSt->dwServiceType = SERVICE_WIN32_OWN_PROCESS;
00261
00262 pSt->dwControlsAccepted = SERVICE_ACCEPT_STOP;
00263
00264 pSt->dwWin32ExitCode = NO_ERROR;
00265
00266 pSt->dwServiceSpecificExitCode = 0;
00267
00268 pSt->dwCurrentState = SERVICE_START_PENDING;
00269
00270 pSt->dwCheckPoint = 1;
00271
00272 pSt->dwWaitHint = 1000;
00273
00274 dbg_err_if(SetServiceStatus(ctx->hServiceStatus, pSt) == 0);
00275
00276 dbg_err_if(parse_opt(argc, argv));
00277
00278
00279 dbg_err_if(app_init());
00280
00281
00282
00283
00284
00285 dbg("SERVICE_RUNNING");
00286 ctx->status.dwCurrentState = SERVICE_RUNNING;
00287 ctx->status.dwCheckPoint = ctx->status.dwWaitHint = 0;
00288 dbg_err_if(!SetServiceStatus(ctx->hServiceStatus, &ctx->status));
00289
00290
00291 app_run();
00292
00293
00294 ctx->status.dwCurrentState = SERVICE_STOPPED;
00295 dbg_err_if(!SetServiceStatus(ctx->hServiceStatus, &ctx->status));
00296
00297 return;
00298
00299 err:
00300 warn_strerror(GetLastError());
00301
00302
00303 ctx->status.dwCurrentState = SERVICE_STOPPED;
00304 dbg_err_if(!SetServiceStatus(ctx->hServiceStatus, &ctx->status));
00305 }
00306
00307 int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
00308 LPSTR lpCmdLine, int nCmdShow)
00309 {
00310 SERVICE_TABLE_ENTRY ServiceTable[] =
00311 {
00312 { ss_name, ServiceMain },
00313 { NULL, NULL }
00314 };
00315 int rc = 0;
00316 const char *name, *desc;
00317
00318 memset(ctx, 0, sizeof(context_t));
00319
00320
00321
00322 dbg_err_if(parse_opt(__argc, __argv));
00323
00324 if(ctx->serv_op)
00325 {
00326
00327 dbg_err_if(app_init());
00328
00329
00330 name = u_config_get_subkey_value(ctx->config, "daemon.name");
00331 if(name)
00332 strncpy(ss_name, name, SS_NAME_BUFSZ);
00333
00334 desc = u_config_get_subkey_value(ctx->config, "daemon.description");
00335 if(desc)
00336 strncpy(ss_desc, desc, SS_DESC_BUFSZ);
00337
00338 if(ctx->serv_op == SERV_INSTALL)
00339 dbg_err_if(InstallService());
00340 else
00341 dbg_err_if(RemoveService());
00342 } else if(ctx->daemon) {
00343 dbg("Starting in service mode...");
00344
00345
00346 if(!StartServiceCtrlDispatcher(ServiceTable))
00347 warn_strerror(GetLastError());
00348 } else {
00349
00350 dbg_err_if(app_init());
00351
00352 rc = app_run();
00353 }
00354
00355 dbg_err_if(app_term());
00356
00357
00358
00359 if(ctx->debug)
00360 return rc;
00361
00362
00363
00364
00365
00366 _exit(rc);
00367 err:
00368 app_term();
00369
00370 if(ctx->debug)
00371 return rc;
00372 _exit(EXIT_FAILURE);
00373 }
00374
00375 #elif defined(OS_UNIX)
00376
00377 int main(int argc, char **argv)
00378 {
00379 int rc = 0;
00380
00381 memset(ctx, 0, sizeof(context_t));
00382
00383
00384 dbg_err_if(parse_opt(argc, argv));
00385
00386 if(getenv("GATEWAY_INTERFACE"))
00387 ctx->cgi = 1;
00388
00389
00390 warn_err_ifm(app_init(), "kloned init error (more info in the log file)");
00391
00392
00393 if(ctx->daemon && !ctx->cgi)
00394 con_err_ifm(daemon(0, 0), "daemon error");
00395
00396
00397 rc = app_run();
00398
00399 dbg_err_if(app_term());
00400
00401
00402
00403 if(ctx->debug)
00404 return rc;
00405
00406
00407
00408
00409
00410 _exit(rc);
00411 err:
00412 app_term();
00413 if(ctx->debug)
00414 return ~0;
00415 _exit(EXIT_FAILURE);
00416 }
00417
00418 #else
00419 #error unsupported platform
00420 #endif
00421