erlsrv_interactive.c

来自「OTP是开放电信平台的简称」· C语言 代码 · 共 1,092 行 · 第 1/2 页

C
1,092
字号
#include <windows.h>#include <winsvc.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include "erlsrv_global.h"#include "erlsrv_registry.h"#include "erlsrv_interactive.h"#include "erlsrv_util.h" /* service_name */#define DBG fprintf(stderr,"argv[0]:%s line %d\n",argv[0],__LINE__)/* Really HAS to correcpond to the enum in erlsrv_registry.h */static char *arg_tab[] = {  "stopaction", "st",  "onfail", "on",  "machine", "m",  "env", "e",  "workdir", "w",  "priority", "p",  "sname", "sn",  "name", "n",  "args", "ar",  "debugtype", "d",  NULL, NULL};static char *generate_real_service_name(char *display_name){  SYSTEMTIME systime;  FILETIME ftime;  char *buff = malloc(strlen(display_name)+		      (8*2)+1);  char *tmp = _strdup(display_name);  int i;  /* 2 Hex chars for each byte in a DWORD */  GetSystemTime(&systime);  SystemTimeToFileTime(&systime,&ftime);  /* Remove trailing version info to avoid user confusion */  for(i = (strlen(tmp)-1);i > 0; --i)    if(tmp[i] == '_'){      tmp[i] = '\0';      break;    }  sprintf(buff,"%s%08x%08x",tmp,ftime.dwHighDateTime,	  ftime.dwLowDateTime);  free(tmp);  return buff;}static int lookup_arg(char *arg){  int i;  if(*arg != '-' && *arg != '/')    return -1;  for(i=0; arg_tab[i] != NULL; i += 2){    if(!_strnicmp(arg_tab[i],arg+1,strlen(arg+1)) &&       !_strnicmp(arg_tab[i+1],arg+1,strlen(arg_tab[i+1])))      return (i / 2);  }  return -1;}char *edit_env(char *edit, char *oldenv){  char **arg;  char *value;  char *name = strdup(edit);  int i;  char *tmp;  arg = env_to_arg(oldenv);  value = strchr(name,'=');  if(value){    *(value++) = '\0';    if(*value == '\0')      value = NULL;  }  for(i=0;arg[i] != NULL; ++i){    tmp = strchr(arg[i],'=');    if(((int) strlen(name)) == (tmp - arg[i]) &&       !_strnicmp(name,arg[i], tmp - arg[i]))      break;  }  if(arg[i] != NULL){    free(arg[i]);    if(value){      arg[i] = strdup(edit);    } else {      do {	arg[i] = arg[i+1];	++i;      } while(arg[i] != NULL);    }  } else if(value){ /* add to arg, which is always allocated		     to hold one extra environment variable*/    arg[i] = strdup(edit);    arg[i+1] = NULL;  }  free(name);  return arg_to_env(arg);}int last_error = 0;void print_last_error(void){  char *mes;  FormatMessage(		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,		NULL,    		(last_error) ? last_error : GetLastError(),		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 		(LPTSTR) &mes,    		0,    		NULL );    fprintf(stderr,"Error: %s",mes);    LocalFree(mes);}    static BOOL install_service(void){  SC_HANDLE scm;  SC_HANDLE service;  char filename[MAX_PATH + 3];  DWORD fnsiz=MAX_PATH;  char dependant[] = { 'L','a','n','m','a','n',		       'W','o','r','k','s','t',		       'a','t','i','o','n','\0','\0'};    if(!(fnsiz = GetModuleFileName(NULL, filename, fnsiz)))    return FALSE;  if(strchr(filename,' ')){    memmove(filename+1,filename,fnsiz);    filename[0] ='\"'; /* " */    filename[fnsiz+1] = '\"'; /* " */    filename[fnsiz+2] = '\0';  }  if((scm = OpenSCManager(NULL, 			  NULL,  			  SC_MANAGER_CONNECT | 			  SC_MANAGER_CREATE_SERVICE))     == NULL){      last_error = GetLastError();      return FALSE;  }  service = CreateService(scm,			  real_service_name,			  service_name,			  SERVICE_ALL_ACCESS & 			  ~(SERVICE_PAUSE_CONTINUE),			  SERVICE_WIN32_OWN_PROCESS,			  SERVICE_AUTO_START,			  SERVICE_ERROR_NORMAL,			  filename,			  NULL,			  NULL,			  dependant,			  NULL, 			  NULL);  if(service == NULL){    CloseServiceHandle(scm);    last_error = GetLastError();    return FALSE;  }  CloseServiceHandle(service);  CloseServiceHandle(scm);  return TRUE;}static BOOL remove_service(void){  SC_HANDLE scm;  SC_HANDLE service;  if((scm = OpenSCManager(NULL, 			  NULL,  			  GENERIC_WRITE))     == NULL)    return FALSE;  service = OpenService(scm,			real_service_name,			SERVICE_ALL_ACCESS);  if(service == NULL){    CloseServiceHandle(scm);    return FALSE;  }  if(!DeleteService(service)){    last_error = GetLastError();    return FALSE;  }  CloseServiceHandle(service);  CloseServiceHandle(scm);  return TRUE;}static BOOL open_service_control(SC_HANDLE *scm, SC_HANDLE *service){  if((*scm = OpenSCManager(NULL, 			  NULL,  			  SC_MANAGER_ALL_ACCESS))     == NULL)    return FALSE;  *service = OpenService(*scm,			real_service_name,			SERVICE_ALL_ACCESS);  if(service == NULL){    CloseServiceHandle(*scm);    return FALSE;  }  return TRUE;}static BOOL open_service_config(SC_HANDLE *scm, SC_HANDLE *service){    if((*scm = OpenSCManager(NULL, 			     NULL,  			     /*GENERIC_WRITE | GENERIC_EXECUTE*/ 			     SC_MANAGER_ALL_ACCESS))       == NULL){	last_error = GetLastError();	return FALSE;    }    *service = OpenService(*scm,			   real_service_name,			   /*GENERIC_WRITE*/			   SERVICE_ALL_ACCESS);    if(service == NULL){	last_error = GetLastError();	CloseServiceHandle(*scm);	return FALSE;    }    return TRUE;}static BOOL wait_service_trans(DWORD initial, DWORD passes, DWORD goal,			       int timeout){  SC_HANDLE scm;  SC_HANDLE service;  int moved = 0;  BOOL ret;  int i;  SERVICE_STATUS stat;  if(! open_service_config(&scm,&service))    return FALSE;  for(i = 0; i < timeout; ++i){    if(!QueryServiceStatus(service,&stat)){      last_error = GetLastError();      ret = FALSE;      goto out;    }    if(stat.dwCurrentState == initial){      if(moved){	ret = FALSE;	/*	 * The exitcode is usually strange when we tried to stop and failed,	 * to report a timeout is more appropriate.	 */	if(goal == SERVICE_STOPPED)	    last_error = ERROR_SERVICE_REQUEST_TIMEOUT;	else	    last_error = stat.dwWin32ExitCode;	goto out;      }    } else if(stat.dwCurrentState == passes){      moved = 1;    } else if(stat.dwCurrentState == goal){      ret = TRUE;      goto out;    }    Sleep(1000);  }  ret = FALSE;  last_error = ERROR_SERVICE_REQUEST_TIMEOUT;out:  CloseServiceHandle(scm);  CloseServiceHandle(service);  return ret;  }static BOOL stop_service(void){  SC_HANDLE scm;  SC_HANDLE service;  BOOL ret;  SERVICE_STATUS ss;  if(!open_service_control(&scm,&service)){#ifdef HARDDEBUG    fprintf(stderr,"Failed to open service.\n");#endif    return FALSE;  }  ret = ControlService(service,SERVICE_CONTROL_STOP,&ss);  if(!ret){    last_error = GetLastError();  }  CloseServiceHandle(service);  CloseServiceHandle(scm);#ifdef HARDDEBUG  if(!ret)  {    fprintf(stderr,"Failed to control service.\n");    print_last_error();  }#endif  return ret;}static BOOL start_service(void){  SC_HANDLE scm;  SC_HANDLE service;  BOOL ret;  if(!open_service_control(&scm,&service))    return FALSE;  ret = StartService(service,0,NULL);  if(!ret){    last_error = GetLastError();  }  CloseServiceHandle(service);  CloseServiceHandle(scm);  return ret;}static BOOL disable_service(void){  SC_HANDLE scm;  SC_HANDLE service;  BOOL ret;  if(!open_service_config(&scm,&service))    return FALSE;  ret = ChangeServiceConfig(service,			    SERVICE_NO_CHANGE,			    SERVICE_DISABLED,			    SERVICE_NO_CHANGE,			    NULL,			    NULL,			    NULL,			    NULL,			    NULL,			    NULL,			    NULL);  if(!ret){    last_error = GetLastError();  }			      CloseServiceHandle(service);  CloseServiceHandle(scm);  return ret;}static BOOL enable_service(void){  SC_HANDLE scm;  SC_HANDLE service;  BOOL ret;if(!open_service_config(&scm,&service))    return FALSE;    ret = ChangeServiceConfig(service,			    SERVICE_NO_CHANGE,			    SERVICE_AUTO_START,			    SERVICE_NO_CHANGE,			    NULL,			    NULL,			    NULL,			    NULL,			    NULL,			    NULL,			    NULL);			      if(!ret){    last_error = GetLastError();  }  CloseServiceHandle(service);  CloseServiceHandle(scm);  return ret;}static BOOL set_interactive(BOOL interactive){    SC_HANDLE scm;    SC_HANDLE service;    BOOL ret;        if(!open_service_config(&scm,&service))	return FALSE;    ret = ChangeServiceConfig(service,			      SERVICE_WIN32_OWN_PROCESS | ((interactive) ?			      SERVICE_INTERACTIVE_PROCESS : 0),			      SERVICE_NO_CHANGE,			      SERVICE_NO_CHANGE,			      NULL,			      NULL,			      NULL,			      NULL,			      NULL,			      NULL,			      NULL);        if(!ret){	last_error = GetLastError();    }    CloseServiceHandle(service);    CloseServiceHandle(scm);    return ret;}RegEntry *old_entries = NULL;BOOL fetch_current(RegEntry *new){  int i;  if(!(old_entries = get_keys(service_name)))    return FALSE;  for(i=0;i<num_reg_entries;++i)    new[i] = old_entries[i];  return TRUE;}void cleanup_old(){  if(old_entries != NULL)    free_keys(old_entries);}BOOL fill_in_defaults(RegEntry *new){  char filename[MAX_PATH];  char *ptr;  if(!GetModuleFileName(NULL, filename, MAX_PATH))    return FALSE;  for(ptr = filename + strlen(filename) - 1;      ptr > filename && *ptr != '\\';      --ptr)    ;  if(*ptr == '\\')    ++ptr;  *ptr = '\0';  ptr = malloc(strlen(filename)+strlen(ERLANG_MACHINE)+1);  strcpy(ptr,filename);  strcat(ptr,ERLANG_MACHINE);  new[StopAction].data.bytes = "";  new[OnFail].data.value = ON_FAIL_IGNORE;  new[Machine].data.bytes = ptr;  new[Machine].data.expand.unexpanded = ptr;  new[Env].data.bytes = "\0";  new[WorkDir].data.bytes = new[WorkDir].data.expand.unexpanded =    "";  new[Priority].data.value = NORMAL_PRIORITY_CLASS;  new[SName].data.bytes = service_name;  new[Name].data.bytes = "";  new[Args].data.bytes = new[Args].data.expand.unexpanded = "";  new[DebugType].data.value = DEBUG_TYPE_NO_DEBUG;  new[InternalServiceName].data.bytes = real_service_name;  return TRUE;}int do_usage(char *arg0){  printf("Usage:\n");  printf("%s {set | add} <servicename>\n"	 "\t[-st[opaction] [<erlang shell command>]]\n"	 "\t[-on[fail] [{reboot | restart | restart_always}]]\n"	 "\t[-m[achine] [<erl-command>]]\n"	 "\t[-e[nv] [<variable>[=<value>]]]\n"	 "\t[-w[orkdir] [<directory>]]\n"	 "\t[-p[riority] [{low|high|realtime}]]\n"	 "\t[{-sn[ame] | -n[ame]} [<nodename>]]\n"	 "\t[-d[ebugtype] [{new|reuse|console}]]\n"	 "\t[-ar[gs] [<limited erl arguments>]]\n\n"	 "%s {start | stop | disable | enable} <servicename>\n\n"	 "%s remove <servicename>\n\n"	 "%s rename <servicename> <servicename>\n\n"	 "%s list [<servicename>]\n\n"	 "%s help\n\n",	 arg0,arg0,arg0,arg0,arg0,arg0);  printf("Manipulates Erlang system services on Windows NT.\n\n");  printf("When no parameter to an option is specified, the option\n"	 "is reset to it's default value. To set an empty argument\n"	 "list, give option -args as last option on command line "	 "with\n"	 "no arguments.\n\n");  printf("Se Erlang documentation for full description.\n");  return 0;}int do_manage(int argc,char **argv){  char *action = argv[1];  RegEntry *current = empty_reg_tab();    if(argc < 3){    fprintf(stderr,"%s: No servicename given!\n",argv[0]);    do_usage(argv[0]);    return 1;  }   service_name = argv[2];  if(!fetch_current(current)){    fprintf(stderr,"%s: The service %s is not an erlsrv controlled service.\n",	    argv[0],service_name);        return 1;  }  real_service_name = _strdup(current[InternalServiceName].data.bytes);  free_keys(current);    if(!_stricmp(action,"start")){    if(!start_service()){      fprintf(stderr,"%s: Failed to start service %s.\n",	      argv[0],service_name);      print_last_error();      return 1;    } else {      if(!wait_service_trans(SERVICE_STOPPED, SERVICE_START_PENDING,			     SERVICE_RUNNING, 60)){	fprintf(stderr,"%s: Failed to start service %s.\n",		argv[0],service_name);	print_last_error();	return 1;      }      printf("%s: Service %s started.\n",	     argv[0],service_name);      return 0;    }  }  if(!_stricmp(action,"stop")){    if(!stop_service()){      fprintf(stderr,"%s: Failed to stop service %s.\n",	      argv[0],service_name);      print_last_error();      return 1;    } else {      if(!wait_service_trans(SERVICE_RUNNING, SERVICE_STOP_PENDING,			     SERVICE_STOPPED, 60)){	fprintf(stderr,"%s: Failed to stop service %s.\n",		argv[0],service_name);	print_last_error();	return 1;      }      printf("%s: Service %s stopped.\n",	     argv[0],service_name);      return 0;    }  }  if(!_stricmp(action,"disable")){#if 0    if(stop_service()){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?