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