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