start_erl.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 639 行
C
639 行
/* * start_erl.c - Windows NT start_erl * * Author: Mattias Nilsson <mattias@erix.ericsson.se> * * Copyright (C) 1998 Ericsson Telecom AB */#define WIN32_LEAN_AND_MEAN#define STRICT#include <stdio.h>#include <stdlib.h>#include <string.h>#include <windows.h>#include <assert.h>char *progname;/* * If CASE_SENSITIVE_OPTIONS is specified, options are case sensitive * (lower case). * The reason for this switch is that _strnicmp is Microsoft specific. */#ifndef CASE_SENSITIVE_OPTIONS#define strnicmp strncmp#else#define strnicmp _strnicmp#endif#define RELEASE_SUBDIR "\\releases"#define REGISTRY_BASE "Software\\Ericsson\\Erlang\\"#define DEFAULT_DATAFILE "start_erl.data"/* Global variables holding option values and command lines */char *CommandLineStart = NULL;char *ErlCommandLine = NULL;char *MyCommandLine = NULL;char *DataFileName = NULL;char *RelDir = NULL;char *BootFlagsFile = NULL;char *BootFlags = NULL;char *RegistryKey = NULL;char *BinDir = NULL;char *RootDir = NULL;char *VsnDir = NULL;char *Version = NULL;char *Release = NULL;BOOL NoConfig=FALSE;PROCESS_INFORMATION ErlProcessInfo;/* * Error reason printout 'the microsoft way' */void ShowLastError(void){ LPVOID lpMsgBuf; DWORD dwErr; dwErr = GetLastError(); if( dwErr == ERROR_SUCCESS ) return; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); fprintf(stderr, lpMsgBuf); LocalFree( lpMsgBuf );}/* * Exit the program and give a nice and firm explanation of why * and how you can avoid it. */void exit_help(char *err){ ShowLastError(); fprintf(stderr, "** Error: %s\n", err); printf("Usage:\n%s\n" " [<erlang options>] ++\n" " [-data <datafile>]\n" " [-reldir <releasedir>]\n" " [-bootflags <bootflagsfile>]\n" " [-noconfig]\n", progname); exit(0);}/* * Splits the command line into two strings: * 1. Options to the Erlang node (ErlCommandLine) * 2. Options to this program (MyCommandLine) */void split_commandline(void){ char *cmdline = CommandLineStart; progname=cmdline; /* Remove the first (quoted) string (our program name) */ if(*cmdline == '"') { cmdline++; /* Skip " */ while( (*cmdline != '\0') && (*cmdline++) != '"' ) ; } else { while( (*cmdline != '\0') && (*cmdline++) != ' ' ) ; } while( (*cmdline) == ' ' ) cmdline++; if( *cmdline == '\0') { ErlCommandLine = ""; MyCommandLine = ""; return; } cmdline[-1] = '\0'; /* Start from the end of the string and search for "++ " (PLUS PLUS SPACE) */ ErlCommandLine = cmdline; if(strncmp(cmdline,"++ ",3)) cmdline = strstr(cmdline," ++ "); if( cmdline == NULL ) { MyCommandLine = ""; return; } /* Terminate the ErlCommandLine where MyCommandLine starts */ *cmdline++ = '\0'; /* Skip 'whitespace--whitespace' (WHITESPACE MINUS MINUS WHITESPACE) */ while( (*cmdline) == ' ' ) cmdline++; while( (*cmdline) == '+' ) cmdline++; while( (*cmdline) == ' ' ) cmdline++; MyCommandLine = cmdline;#ifdef _DEBUG fprintf(stderr, "ErlCommandLine: '%s'\n", ErlCommandLine); fprintf(stderr, "MyCommandLine: '%s'\n", MyCommandLine);#endif}/* * 'Smart' unquoting of a string: \" becomes " and " becomes (nothing) * Skips any leading spaces and parses up to NULL or end of quoted string. * Calls exit_help() if an unterminated quote is detected. */char * unquote_optionarg(char *str, char **strp){ char *newstr = (char *)malloc(strlen(str)+1); /* This one is realloc:ed later */ int i=0, inquote=0; assert(newstr); assert(str); /* Skip leading spaces */ while( *str == ' ' ) str++; /* Loop while in quote or until EOS or unquoted space */ while( (inquote==1) || ( (*str!=0) && (*str!=' ') ) ) { switch( *str ) { case '\\': /* If we are inside a quoted string we should convert \c to c */ if( inquote && str[1] == '"' ) str++; newstr[i++]=*str++; break; case '"': inquote = 1-inquote; *str++; break; default: newstr[i++]=*str++; break; } if( (*str == 0) && (inquote==1) ) { exit_help("Unterminated quote."); } } newstr[i++] = 0x00; /* Update the supplied pointer (used for continued parsing of options) */ *strp = str; /* Adjust memblock of newstr */ newstr = (char *)realloc(newstr, i); assert(newstr); return(newstr);}/* * Parses MyCommandLine and tries to fill in all the required option variables * (one way or another). */void parse_commandline(void){ char *cmdline = MyCommandLine; while( *cmdline != '\0' ) { switch( *cmdline ) { case '-': /* Handle both -arg and /arg */ case '/': *cmdline++; if( strnicmp(cmdline, "data", 4) == 0) { DataFileName = unquote_optionarg(cmdline+4, &cmdline); } else if( strnicmp(cmdline, "reldir", 6) == 0) { RelDir = unquote_optionarg(cmdline+6, &cmdline);#ifdef _DEBUG fprintf(stderr, "RelDir: '%s'\n", RelDir);#endif } else if( strnicmp(cmdline, "bootflags", 9) == 0) { BootFlagsFile = unquote_optionarg(cmdline+9, &cmdline); } else if( strnicmp(cmdline, "noconfig", 8) == 0) { NoConfig=TRUE;#ifdef _DEBUG fprintf(stderr, "NoConfig=TRUE\n");#endif } else { fprintf(stderr, "Unkown option: '%s'\n", cmdline); exit_help("Unknown command line option"); } break; default: cmdline++; break; } }}/* * Read the data file specified and get the version and release number * from it. * * This function also construct the correct RegistryKey from the version information * retrieved. */void read_datafile(void){ FILE *fp; char *newname; long size; if(!DataFileName){ DataFileName = malloc(strlen(DEFAULT_DATAFILE) + 1); strcpy(DataFileName,DEFAULT_DATAFILE); } /* Is DataFileName relative or absolute ? */ if( (DataFileName[0] != '\\') && (strncmp(DataFileName+1, ":\\", 2)!=0) ) { /* Relative name, we have to prepend RelDir to it. */ if( !RelDir ) { exit_help("Need -reldir when -data filename has relative path."); } else { newname = (char *)malloc(strlen(DataFileName)+strlen(RelDir)+2); assert(newname); sprintf(newname, "%s\\%s", RelDir, DataFileName); free(DataFileName); DataFileName=newname; } }#ifdef _DEBUG fprintf(stderr, "DataFileName: '%s'\n", DataFileName);#endif if( (fp=fopen(DataFileName, "rb")) == NULL) { exit_help("Cannot find the datafile."); } fseek(fp, 0, SEEK_END); size=ftell(fp); fseek(fp, 0, SEEK_SET); Version = (char *)malloc(size+1); Release = (char *)malloc(size+1); assert(Version); assert(Release); if( (fscanf(fp, "%s %s", Version, Release)) == 0) { fclose(fp); exit_help("Format error in datafile."); } fclose(fp);#ifdef _DEBUG fprintf(stderr, "DataFile version: '%s'\n", Version); fprintf(stderr, "DataFile release: '%s'\n", Release);#endif}/* * Read the registry keys we need */void read_registry_keys(void){ HKEY hReg; ULONG lLen; /* Create the RegistryKey name */ RegistryKey = (char *) malloc(strlen(REGISTRY_BASE) + strlen(Version) + 1); assert(RegistryKey); sprintf(RegistryKey, REGISTRY_BASE "%s", Version); /* We always need to find BinDir */ if( (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegistryKey, 0, KEY_READ, &hReg)) != ERROR_SUCCESS ) { exit_help("Could not open registry key."); } /* First query size of data */ if( (RegQueryValueEx(hReg, "Bindir", NULL, NULL, NULL, &lLen)) != ERROR_SUCCESS) { exit_help("Failed to query BinDir of release.\n"); } /* Allocate enough space */ BinDir = (char *)malloc(lLen+1); assert(BinDir); /* Retrieve the value */ if( (RegQueryValueEx(hReg, "Bindir", NULL, NULL, (unsigned char *) BinDir, &lLen)) != ERROR_SUCCESS) { exit_help("Failed to query BinDir of release (2).\n"); }#ifdef _DEBUG fprintf(stderr, "Bindir: '%s'\n", BinDir);#endif /* We also need the rootdir, in case we need to build RelDir later */ /* First query size of data */ if( (RegQueryValueEx(hReg, "Rootdir", NULL, NULL, NULL, &lLen)) != ERROR_SUCCESS) { exit_help("Failed to query RootDir of release.\n"); } /* Allocate enough space */ RootDir = (char *) malloc(lLen+1); assert(RootDir); /* Retrieve the value */ if( (RegQueryValueEx(hReg, "Rootdir", NULL, NULL, (unsigned char *) RootDir, &lLen)) != ERROR_SUCCESS) { exit_help("Failed to query RootDir of release (2).\n"); }#ifdef _DEBUG fprintf(stderr, "Rootdir: '%s'\n", RootDir);#endif RegCloseKey(hReg);}/* * Read the bootflags. This file contains extra command line options to erl.exe */void read_bootflags(void){ FILE *fp; long fsize; char *newname; if(BootFlagsFile) { /* Is BootFlagsFile relative or absolute ? */ if( (BootFlagsFile[0] != '\\') && (strncmp(BootFlagsFile+1, ":\\", 2)!=0) ) { /* Relative name, we have to prepend RelDir\\Version to it. */ if( !RelDir ) { exit_help("Need -reldir when -bootflags " "filename has relative path."); } else { newname = (char *)malloc(strlen(BootFlagsFile)+strlen(RelDir)+strlen(Release)+3); assert(newname); sprintf(newname, "%s\\%s\\%s", RelDir, Release, BootFlagsFile); free(BootFlagsFile); BootFlagsFile=newname; } } #ifdef _DEBUG fprintf(stderr, "BootFlagsFile: '%s'\n", BootFlagsFile);#endif if( (fp=fopen(BootFlagsFile, "rb")) == NULL) { exit_help("Could not open BootFlags file."); } fseek(fp, 0, SEEK_END); fsize=ftell(fp); fseek(fp, 0, SEEK_SET); BootFlags = (char *)malloc(fsize+1); assert(BootFlags); if( (fgets(BootFlags, fsize+1, fp)) == NULL) { exit_help("Error while reading BootFlags file"); } fclose(fp); /* Adjust buffer size */ BootFlags = (char *)realloc(BootFlags, strlen(BootFlags)+1); assert(BootFlags); /* Strip \r\n from BootFlags */ fsize = strlen(BootFlags); while( fsize > 0 && ( (BootFlags[fsize-1] == '\r') || (BootFlags[fsize-1] == '\n') ) ) { BootFlags[--fsize]=0; } } else { /* Set empty BootFlags */ BootFlags = ""; } #ifdef _DEBUG fprintf(stderr, "BootFlags: '%s'\n", BootFlags);#endif}long start_new_node(void){ char *CommandLine; unsigned long i; STARTUPINFO si; DWORD dwExitCode; i = strlen(RelDir) + strlen(Release) + 4; VsnDir = (char *)malloc(i); assert(VsnDir); sprintf(VsnDir, "%s\\%s", RelDir, Release); if( NoConfig ) { i = strlen(BinDir) + strlen(ErlCommandLine) + strlen(BootFlags) + 64; CommandLine = (char *)malloc(i); assert(CommandLine); sprintf(CommandLine, "\"%s\\erl.exe\" -boot \"%s\\start\" %s %s", BinDir, VsnDir, ErlCommandLine, BootFlags); } else { i = strlen(BinDir) + strlen(ErlCommandLine) + strlen(BootFlags) + strlen(VsnDir)*2 + 64; CommandLine = (char *)malloc(i); assert(CommandLine); sprintf(CommandLine, "\"%s\\erl.exe\" -boot \"%s\\start\" -config \"%s\\sys\" %s %s", BinDir, VsnDir, VsnDir, ErlCommandLine, BootFlags); }#ifdef _DEBUG fprintf(stderr, "CommandLine: '%s'\n", CommandLine);#endif /* Initialize the STARTUPINFO structure. */ memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.lpTitle = NULL; si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle(STD_ERROR_HANDLE); /* Create the new Erlang process */ if( (CreateProcess( NULL, /* pointer to name of executable module */ CommandLine, /* pointer to command line string */ NULL, /* pointer to process security attributes */ NULL, /* pointer to thread security attributes */ TRUE, /* handle inheritance flag */ GetPriorityClass(GetCurrentProcess()), /* creation flags */ NULL, /* pointer to new environment block */ BinDir,/* pointer to current directory name */ &si, /* pointer to STARTUPINFO */ &ErlProcessInfo /* pointer to PROCESS_INFORMATION */ )) == FALSE) { ShowLastError(); exit_help("Failed to start new node"); }#ifdef _DEBUG fprintf(stderr, "Waiting for Erlang to terminate.\n");#endif if(MsgWaitForMultipleObjects(1,&ErlProcessInfo.hProcess, FALSE, INFINITE, QS_POSTMESSAGE) == WAIT_OBJECT_0+1){ if(PostThreadMessage(ErlProcessInfo.dwThreadId, WM_USER, (WPARAM) 0, (LPARAM) 0)){ /* Wait 10 seconds for erl process to die, elsee terminate it. */ if(WaitForSingleObject(ErlProcessInfo.hProcess, 10000) != WAIT_OBJECT_0){ TerminateProcess(ErlProcessInfo.hProcess,0); } } else { TerminateProcess(ErlProcessInfo.hProcess,0); } } GetExitCodeProcess(ErlProcessInfo.hProcess, &dwExitCode);#ifdef _DEBUG fprintf(stderr, "Erlang terminated.\n");#endif free(CommandLine); return(dwExitCode);}/* * Try to make the needed options complete by looking through the data file, * environment variables and registry entries. */void complete_options(void){ /* Try to find a descent RelDir */ if( !RelDir ) { if( (RelDir=getenv("RELDIR")) == NULL ) { if(DataFileName){ /* Needs to be absolute for this to work, but we can try... */ read_datafile(); read_registry_keys(); } else { /* Impossible to find all data... */ exit_help("Need either Release directory or an absolute " "datafile name."); } /* Ok, construct our own RelDir from RootDir */ RelDir = (char *) malloc(strlen(RootDir)+strlen(RELEASE_SUBDIR)+1); assert(RelDir); sprintf(RelDir, "%s" RELEASE_SUBDIR, RootDir); } else { read_datafile(); read_registry_keys(); } } else { read_datafile(); read_registry_keys(); } read_bootflags(); #ifdef _DEBUG fprintf(stderr, "RelDir: '%s'\n", RelDir);#endif}BOOL WINAPI LogoffHandlerRoutine( DWORD dwCtrlType ){ if(dwCtrlType == CTRL_LOGOFF_EVENT) { return TRUE; } return FALSE;}int main(void){ DWORD dwExitCode; char *cmdline; /* Make sure a logoff does not distrurb us. */ SetConsoleCtrlHandler(LogoffHandlerRoutine, TRUE); cmdline = GetCommandLine(); assert(cmdline); CommandLineStart = (char *) malloc(strlen(cmdline) + 1); assert(CommandLineStart); strcpy(CommandLineStart,cmdline); split_commandline(); parse_commandline(); complete_options(); /* We now have all the options we need in order to fire up a new node.. */ dwExitCode = start_new_node(); return( (int) dwExitCode );}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?