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