bool TraceManager::check_result(ITracePlugin* plugin, const char* module, const char* function, bool result) { if (result) return true; if (!plugin) { gds__log("Trace plugin %s returned error on call %s, " "did not create plugin and provided no additional details on reasons of failure", module, function); return false; } const char* errorStr = plugin->trace_get_error(); if (!errorStr) { gds__log("Trace plugin %s returned error on call %s, " "but provided no additional details on reasons of failure", module, function); return false; } gds__log("Trace plugin %s returned error on call %s.\n\tError details: %s", module, function, errorStr); return false; }
// create directory for lock files and set appropriate access rights void createLockDirectory(const char* pathname) { static bool errorLogged = false; DWORD attr = GetFileAttributes(pathname); DWORD errcode = 0; if (attr == INVALID_FILE_ATTRIBUTES) { errcode = GetLastError(); if (errcode == ERROR_FILE_NOT_FOUND) { if (!CreateDirectory(pathname, NULL)) { errcode = GetLastError(); } else { adjustLockDirectoryAccess(pathname); attr = GetFileAttributes(pathname); if (attr == INVALID_FILE_ATTRIBUTES) { errcode = GetLastError(); } } } } Firebird::string err; if (attr == INVALID_FILE_ATTRIBUTES) { err.printf("Can't create directory \"%s\". OS errno is %d", pathname, errcode); if (!errorLogged) { errorLogged = true; gds__log(err.c_str()); } Firebird::fatal_exception::raise(err.c_str()); } if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { err.printf("Can't create directory \"%s\". File with same name already exists", pathname); if (!errorLogged) { errorLogged = true; gds__log(err.c_str()); } Firebird::fatal_exception::raise(err.c_str()); } if (attr & FILE_ATTRIBUTE_READONLY) { err.printf("Can't create directory \"%s\". Readonly directory with same name already exists", pathname); if (!errorLogged) { errorLogged = true; gds__log(err.c_str()); } Firebird::fatal_exception::raise(err.c_str()); } }
void iscLogStatus(const TEXT* text, const ISC_STATUS* status_vector) { /************************************** * * i s c L o g S t a t u s * ************************************** * * Functional description * Log error to error log. * **************************************/ fb_assert(status_vector[1] != FB_SUCCESS); try { Firebird::string buffer(text ? text : ""); TEXT temp[BUFFER_LARGE]; while (fb_interpret(temp, sizeof(temp), &status_vector)) { if (!buffer.isEmpty()) { buffer += "\n\t"; } buffer += temp; } gds__log("%s", buffer.c_str()); } catch (const Firebird::Exception&) {} // no-op }
void CNTL_stop_service() //const TEXT* service) // unused param { /************************************** * * C N T L _ s t o p _ s e r v i c e * ************************************** * * Functional description * This function is called to stop the service. * * **************************************/ SC_HANDLE servicemgr_handle = OpenSCManager(NULL, NULL, GENERIC_READ); if (servicemgr_handle == NULL) { // return error int error = GetLastError(); gds__log("SC manager error %d", error); return; } SC_HANDLE service_handleL = OpenService(servicemgr_handle, service_name->c_str(), GENERIC_READ | GENERIC_EXECUTE); if (service_handleL == NULL) { // return error int error = GetLastError(); gds__log("open services error %d", error); return; } else { SERVICE_STATUS status_info; if (!ControlService (service_handleL, SERVICE_CONTROL_STOP, &status_info)) { // return error const int error = GetLastError(); gds__log("Control services error %d", error); return; } } }
pid_t UTIL_start_process(const char* process, const char* process2, char** argv, const char* prog_name) { /************************************** * * U T I L _ s t a r t _ p r o c e s s * ************************************** * * Functional description * * This function is used to create the specified process, * * Returns Codes: * -1 Process spawn failed. * pid Successful creation. PID is returned. * * Note: Make sure that the argument list ends with a null * and the first argument is large enough to hold the complete * expanded process name. (MAXPATHLEN recommended) * **************************************/ fb_assert(process != NULL); fb_assert(argv != NULL); // prepend Firebird home directory to the program name // choose correct (super/superclassic) image - to be removed in 3.0 Firebird::PathName string = fb_utils::getPrefix(fb_utils::FB_DIR_SBIN, process); if (access(string.c_str(), X_OK) < 0) { string = fb_utils::getPrefix(fb_utils::FB_DIR_SBIN, process2); } if (prog_name) { gds__log("%s: guardian starting %s\n", prog_name, string.c_str()); } // add place in argv for visibility to "ps" strcpy(argv[0], string.c_str()); #if (defined SOLARIS) pid_t pid = fork1(); if (!pid) { if (execv(string.c_str(), argv) == -1) { //ib_fprintf(ib_stderr, "Could not create child process %s with args %s\n", string, argv); } exit(FINI_ERROR); } #else pid_t pid = vfork(); if (!pid) { execv(string.c_str(), argv); _exit(FINI_ERROR); } #endif return (pid); }
static int wait_threads(const int, const int, void*) { server_shutdown = true; if (!ThreadCounter::wait()) { gds__log("Timeout expired during remote server shutdown"); } return FB_SUCCESS; }
static void raiseLimit(int resource) { struct rlimit lim; if (getrlimit(resource, &lim) == 0) { if (lim.rlim_cur != lim.rlim_max) { lim.rlim_cur = lim.rlim_max; if (setrlimit(resource, &lim) != 0) { gds__log("setrlimit() failed, errno=%d", errno); } } } else { gds__log("getrlimit() failed, errno=%d", errno); } }
HWND DisplayPropSheet(HWND hParentWnd, HINSTANCE hInst) { /****************************************************************************** * * D i s p l a y P r o p S h e e t * ****************************************************************************** * * Input: hParentWnd - Handle to the main window of this application * * Return: Handle to the Property sheet dialog if successful * NULL if error in displaying property sheet * * Description: This function initializes the page(s) of the property sheet, * and then calls the PropertySheet() function to display it. *****************************************************************************/ PROPSHEETPAGE PSPages[1]; HINSTANCE hInstance = hInst; PSPages[0].dwSize = sizeof(PROPSHEETPAGE); PSPages[0].dwFlags = PSP_USETITLE; PSPages[0].hInstance = hInstance; PSPages[0].pszTemplate = MAKEINTRESOURCE(IDD_PROPSHEET); PSPages[0].pszTitle = MAKEINTRESOURCE(IDS_PROP_TITLE); PSPages[0].pfnDlgProc = (DLGPROC) GeneralPage; PSPages[0].pfnCallback = NULL; PROPSHEETHEADER PSHdr; PSHdr.dwSize = sizeof(PROPSHEETHEADER); PSHdr.dwFlags = PSH_PROPTITLE | PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_MODELESS | PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP; PSHdr.hwndParent = hParentWnd; PSHdr.hInstance = hInstance; PSHdr.pszIcon = MAKEINTRESOURCE(IDI_IBGUARD); PSHdr.pszCaption = (LPSTR) GUARDIAN_APP_LABEL; PSHdr.nPages = FB_NELEM(PSPages); PSHdr.nStartPage = 0; PSHdr.ppsp = (LPCPROPSHEETPAGE) & PSPages; PSHdr.pfnCallback = NULL; hPSDlg = (HWND) PropertySheet(&PSHdr); if (hPSDlg == 0 || hPSDlg == (HWND) -1) { gds__log("Create property sheet window failed. Error code %d", GetLastError()); hPSDlg = NULL; } return hPSDlg; }
static THREAD_ENTRY_DECLARE xnet_connect_wait_thread(THREAD_ENTRY_PARAM) { /************************************** * * x n e t _ c o n n e c t _ w a i t _ t h r e a d * ************************************** * * Functional description * Starts xnet server side interprocess thread * **************************************/ ThreadCounter counter; ISC_STATUS_ARRAY status_vector; while (!server_shutdown) { fb_utils::init_status(status_vector); rem_port* port = XNET_connect(/*NULL,*/ NULL, status_vector, server_flag); if (!port) { const ISC_STATUS err = status_vector[1]; if (err) { if (err == isc_net_server_shutdown) break; gds__log_status(0, status_vector); } } else if (gds__thread_start(process_connection_thread, port, THREAD_medium, 0, 0)) { gds__log("XNET: can't start worker thread, connection terminated"); port->disconnect(NULL, NULL); } } return 0; }
static THREAD_ENTRY_DECLARE inet_connect_wait_thread(THREAD_ENTRY_PARAM) { /************************************** * * i n e t _ c o n n e c t _ w a i t _ t h r e a d * ************************************** * * Functional description * **************************************/ ThreadCounter counter; ISC_STATUS_ARRAY status_vector; while (!server_shutdown) { fb_utils::init_status(status_vector); rem_port* port = INET_connect(protocol_inet, NULL, status_vector, server_flag, 0); if (!port) { if (status_vector[1]) { gds__log_status(0, status_vector); } break; } if (server_flag & SRVR_multi_client) { SRVR_multi_thread(port, server_flag); break; } if (gds__thread_start(process_connection_thread, port, THREAD_medium, 0, 0)) { gds__log("INET: can't start worker thread, connection terminated"); port->disconnect(NULL, NULL); } } return 0; }
static THREAD_ENTRY_DECLARE WINDOW_main(THREAD_ENTRY_PARAM) { /************************************** * * W I N D O W _ m a i n * ************************************** * * Functional description * * This function is where the actual service code starts. * Do all the window init stuff, then fork off a thread for starting * the server. * **************************************/ // If we're a service, don't create a window if (service_flag) { try { Thread::start(start_and_watch_server, 0, THREAD_medium, &watcher_thd); } catch (const Firebird::Exception&) { // error starting server thread char szMsgString[256]; LoadString(hInstance_gbl, IDS_CANT_START_THREAD, szMsgString, 256); gds__log(szMsgString); } return 0; } // Make sure that there is only 1 instance of the guardian running HWND hWnd = FindWindow(GUARDIAN_CLASS_NAME, GUARDIAN_APP_NAME); if (hWnd) { char szMsgString[256]; LoadString(hInstance_gbl, IDS_ALREADYSTARTED, szMsgString, 256); MessageBox(NULL, szMsgString, GUARDIAN_APP_LABEL, MB_OK | MB_ICONSTOP); gds__log(szMsgString); return 0; } // initialize main window WNDCLASS wcl; wcl.hInstance = hInstance_gbl; wcl.lpszClassName = GUARDIAN_CLASS_NAME; wcl.lpfnWndProc = WindowFunc; wcl.style = 0; wcl.hIcon = LoadIcon(hInstance_gbl, MAKEINTRESOURCE(IDI_IBGUARD)); wcl.hCursor = LoadCursor(NULL, IDC_ARROW); wcl.lpszMenuName = NULL; wcl.cbClsExtra = 0; wcl.cbWndExtra = 0; wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); if (!RegisterClass(&wcl)) { char szMsgString[256]; LoadString(hInstance_gbl, IDS_REGERROR, szMsgString, 256); MessageBox(NULL, szMsgString, GUARDIAN_APP_LABEL, MB_OK | MB_ICONSTOP); return 0; } hWnd = CreateWindowEx(0, GUARDIAN_CLASS_NAME, GUARDIAN_APP_NAME, WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance_gbl, NULL); // Save the window handle for the thread hWndGbl = hWnd; // begin a new thread for calling the start_and_watch_server try { Thread::start(start_and_watch_server, 0, THREAD_medium, NULL); } catch (const Firebird::Exception&) { // error starting server thread char szMsgString[256]; LoadString(hInstance_gbl, IDS_CANT_START_THREAD, szMsgString, 256); MessageBox(NULL, szMsgString, GUARDIAN_APP_LABEL, MB_OK | MB_ICONSTOP); gds__log(szMsgString); DestroyWindow(hWnd); return 0; } SendMessage(hWnd, WM_COMMAND, IDM_CANCEL, 0); UpdateWindow(hWnd); MSG message; while (GetMessage(&message, NULL, 0, 0)) { if (hPSDlg) { // If property sheet dialog is open // Check if the message is property sheet dialog specific BOOL bPSMsg = PropSheet_IsDialogMessage(hPSDlg, &message); // Check if the property sheet dialog is still valid, if not destroy it if (!PropSheet_GetCurrentPageHwnd(hPSDlg)) { DestroyWindow(hPSDlg); hPSDlg = NULL; if (swap_icons_thd) { CloseHandle(swap_icons_thd); swap_icons_thd = 0; }; } if (bPSMsg) continue; } TranslateMessage(&message); DispatchMessage(&message); } return message.wParam; }
static void write_log(int log_action, const char* buff) { /****************************************************************************** * * w r i t e _ l o g * ****************************************************************************** * * Description: Writes the guardian information to either the Windows 95 * property sheet structure (log_entry) or to the Windows NT * Event Log *****************************************************************************/ const size_t BUFF_SIZE = 512; char tmp_buff[BUFF_SIZE]; // Move to the end of the log_entry list log_info* log_temp = log_entry; while (log_temp->next) log_temp = log_temp->next; log_info* tmp = static_cast<log_info*>(malloc(sizeof(log_info))); memset(tmp, 0, sizeof(log_info)); #ifdef NOT_USED_OR_REPLACED time_t ltime; time(<ime); const tm* today = localtime(<ime); sprintf(tmp->log_time, "%02d:%02d", today->tm_hour, today->tm_min); sprintf(tmp->log_date, "%02d/%02d/%02d", today->tm_mon + 1, today->tm_mday, today->tm_year % 100); #else // TMN: Fixed this after bug-report. Should it really force // 24hr format in e.g US, where they use AM/PM wharts? GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS | TIME_FORCE24HOURFORMAT, NULL, NULL, tmp->log_time, sizeof(tmp->log_time)); GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, tmp->log_date, sizeof(tmp->log_date)); #endif if (log_action >= IDS_LOG_START && log_action <= IDS_LOG_TERM) { // Only Windows 95 needs this information since it goes in the property sheet LoadString(hInstance_gbl, log_action, tmp_buff, sizeof(tmp->log_action)); sprintf(tmp->log_action, "%s", tmp_buff); tmp->next = NULL; log_temp->next = tmp; } if (service_flag) { // on NT HANDLE hLog = RegisterEventSource(NULL, service_name->c_str()); if (!hLog) gds__log("Error opening Windows NT Event Log"); else { char buffer[BUFF_SIZE]; char* act_buff[1]; act_buff[0] = buffer; LoadString(hInstance_gbl, log_action + 1, tmp_buff, sizeof(tmp_buff)); sprintf(act_buff[0], "%s", buff); LPTSTR lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING, tmp_buff, 0, 0, (LPTSTR) &lpMsgBuf, 0, reinterpret_cast<va_list*>(act_buff)); const int len = MIN(BUFF_SIZE - 1, strlen(lpMsgBuf) - 1); strncpy(act_buff[0], lpMsgBuf, len); act_buff[0][len] = 0; LocalFree(lpMsgBuf); WORD wLogType; switch (log_action) { case IDS_LOG_START: case IDS_LOG_STOP: wLogType = EVENTLOG_INFORMATION_TYPE; break; default: wLogType = EVENTLOG_ERROR_TYPE; } if (!ReportEvent (hLog, wLogType, 0, log_action + 1, NULL, 1, 0, const_cast<const char**>(act_buff), NULL)) { FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) & lpMsgBuf, 0, NULL); gds__log("Unable to update NT Event Log.\n\tOS Message: %s", lpMsgBuf); LocalFree(lpMsgBuf); } DeregisterEventSource(hLog); } } // Write to the Firebird log if (*buff) gds__log(buff); }
static HANDLE parse_args(LPCSTR lpszArgs, USHORT* pserver_flag) { /************************************** * * p a r s e _ a r g s * ************************************** * * Functional description * WinMain gives us a stupid command string, not * a cool argv. Parse through the string and * set the options. * Returns * a connection handle if one was passed in, * INVALID_HANDLE_VALUE otherwise. * **************************************/ bool delimited = false; HANDLE connection_handle = INVALID_HANDLE_VALUE; const TEXT* p = lpszArgs; while (*p) { TEXT c; if (*p++ == '-') { while ((*p) && (c = *p++) && (c != ' ')) { switch (UPPER(c)) { case 'A': *pserver_flag |= SRVR_non_service; break; case 'B': *pserver_flag |= SRVR_high_priority; break; case 'D': *pserver_flag |= (SRVR_debug | SRVR_non_service); break; #ifndef SUPERSERVER case 'H': while (*p && *p == ' ') p++; if (*p) { TEXT buffer[32]; char* pp = buffer; while (*p && *p != ' ' && (pp - buffer < sizeof(buffer) - 1)) { if (*p == '@') { p++; *pp++ = '\0'; connection_handle = (HANDLE) _atoi64(buffer); pp = buffer; } else *pp++ = *p++; } *pp++ = '\0'; if (connection_handle == INVALID_HANDLE_VALUE) { connection_handle = (HANDLE) _atoi64(buffer); } else { const DWORD parent_id = atol(buffer); const HANDLE parent_handle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, parent_id); if (!parent_handle) { gds__log("SERVER: OpenProcess failed. Errno = %d, parent PID = %d", GetLastError(), parent_id); exit(FINI_ERROR); } if (!DuplicateHandle(parent_handle, connection_handle, GetCurrentProcess(), &connection_handle, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) { gds__log("SERVER: DuplicateHandle failed. Errno = %d, parent PID = %d", GetLastError(), parent_id); exit(FINI_ERROR); } CloseHandle(parent_handle); } } break; #endif case 'I': *pserver_flag |= SRVR_inet; break; case 'M': *pserver_flag |= SRVR_multi_client; break; case 'N': *pserver_flag |= SRVR_no_icon; break; case 'P': // Specify a port or named pipe other than the default while (*p && *p == ' ') p++; if (*p) { // Assumed the buffer size for both protocols may differ // in the future, hence I did generic code. char* pi = protocol_inet; const char* piend = protocol_inet + sizeof(protocol_inet) - 1; char* pw = protocol_wnet; const char* pwend = protocol_wnet + sizeof(protocol_wnet) - 1; *pi++ = '/'; *pw++ = '\\'; *pw++ = '\\'; *pw++ = '.'; *pw++ = '@'; while (*p && *p != ' ') { if (pi < piend) *pi++ = *p; if (pw < pwend) *pw++ = *p++; } *pi++ = '\0'; *pw++ = '\0'; } break; case 'R': *pserver_flag &= ~SRVR_high_priority; break; case 'S': delimited = false; while (*p && *p == ' ') p++; if (*p && *p == '"') { p++; delimited = true; } if (delimited) { char* pi = instance; const char* pend = instance + sizeof(instance) - 1; while (*p && *p != '"' && pi < pend) { *pi++ = *p++; } *pi++ = '\0'; if (*p && *p == '"') p++; } else { if (*p && *p != '-') { char* pi = instance; const char* pend = instance + sizeof(instance) - 1; while (*p && *p != ' ' && pi < pend) { *pi++ = *p++; } *pi++ = '\0'; } } break; case 'W': *pserver_flag |= SRVR_wnet; break; case 'X': *pserver_flag |= SRVR_xnet; break; case 'Z': // CVC: printf doesn't work because we don't have a console attached. //printf("Firebird remote server version %s\n", FB_VERSION); MessageBox(NULL, FB_VERSION, "Firebird server version", MB_OK | MB_ICONINFORMATION | MB_TOPMOST | MB_DEFAULT_DESKTOP_ONLY); exit(FINI_OK); default: // In case of something unrecognized, just // continue, since we have already taken it off // of p. break; } } } } if ((*pserver_flag & (SRVR_inet | SRVR_wnet | SRVR_xnet)) == 0) { *pserver_flag |= SRVR_wnet; *pserver_flag |= SRVR_inet; *pserver_flag |= SRVR_xnet; } return connection_handle; }
int FB_EXPORTED server_main( int argc, char** argv) { /************************************** * * m a i n * ************************************** * * Functional description * Run the server with apollo mailboxes. * **************************************/ RemPortPtr port; // 01 Sept 2003, Nickolay Samofatov // In GCC version 3.1-3.3 we need to install special error handler // in order to get meaningful terminate() error message on stderr. // In GCC 3.4 or later this is the default. //#if __GNUC__ == 3 && __GNUC_MINOR__ >= 1 && __GNUC_MINOR__ < 4 // std::set_terminate (__gnu_cxx::__verbose_terminate_handler); //#endif const TEXT* const* const end = argc + argv; argv++; bool debug = false, standalone = false; INET_SERVER_flag = 0; int channel = 0; protocol[0] = 0; bool multi_client = false, multi_threaded = false; #ifdef SUPERSERVER INET_SERVER_flag |= SRVR_multi_client; multi_client = multi_threaded = standalone = true; #endif int clients = 0; bool done = false; while (argv < end) { TEXT c; const TEXT* p = *argv++; if (*p++ == '-') while (c = *p++) { switch (UPPER(c)) { case 'D': INET_SERVER_flag |= SRVR_debug; debug = true; break; #ifndef SUPERSERVER case 'M': INET_SERVER_flag |= SRVR_multi_client; if (argv < end) { if (clients = atoi(*argv)) argv++; } multi_client = standalone = true; break; case 'S': standalone = true; break; case 'I': standalone = false; break; case 'T': multi_threaded = true; break; case 'U': multi_threaded = false; break; #endif // SUPERSERVER case 'E': if (ISC_set_prefix(p, *argv) == -1) printf("Invalid argument Ignored\n"); else argv++; // do not skip next argument if this one is invalid done = true; break; case 'P': fb_utils::snprintf(protocol, sizeof(protocol), "/%s", *argv++); break; case 'H': case '?': printf("Firebird TCP/IP server options are:\n"); printf(" -d : debug on\n"); #ifndef SUPERSERVER // These options are not applicable to super server printf(" -m : multiclient - on\n"); printf(" -s : standalone - true\n"); printf(" -i : standalone - false\n"); printf(" -t : multithread - true (non pc only)\n"); printf(" -u : multithread - false (pc only)\n"); #endif printf(" -p<protocol> : specify protocol\n"); printf(" -h|? : print this help\n"); printf("\n"); printf(" (The following -e options used to be -h options)\n"); printf(" -e <firebird_root_dir> : set firebird_root path\n"); printf(" -el <firebird_lock_dir> : set runtime firebird_lock dir\n"); printf(" -em <firebird_msg_dir> : set firebird_msg dir path\n"); printf(" -z : print version\n"); exit(FINI_OK); case 'Z': printf("Firebird TCP/IP server version %s\n", GDS_VERSION); exit(FINI_OK); } if (done) break; } } // activate paths set with -e family of switches ISC_set_prefix(0, 0); #ifdef UNIX set_signal(SIGPIPE, signal_handler); set_signal(SIGUSR1, signal_handler); set_signal(SIGUSR2, signal_handler); #endif #if defined(UNIX) && defined(HAVE_SETRLIMIT) && defined(HAVE_GETRLIMIT) #ifdef RLIMIT_NPROC raiseLimit(RLIMIT_NPROC); #endif #if !(defined(DEV_BUILD)) if (Config::getBugcheckAbort()) #endif { // try to force core files creation raiseLimit(RLIMIT_CORE); // we need some writable directory for core file // on any unix /tmp seems to be the best place if (CHANGE_DIR(TEMP_DIR)) { // error on changing the directory gds__log("Could not change directory to %s due to errno %d", TEMP_DIR, errno); } } #if defined(SUPERSERVER) && (defined SOLARIS || defined HPUX || defined LINUX) // Increase max open files to hard limit for Unix // platforms which are known to have low soft limits. raiseLimit(RLIMIT_NOFILE); #endif #endif // Fork off a server, wait for it to die, then fork off another, // but give up after 100 tries #ifndef SUPERSERVER if (multi_client && !debug) { #ifdef UNIX set_signal(SIGUSR1, signal_handler); #endif int child; for (int n = 0; n < 100; n++) { INET_SERVER_start = 0; if (!(child = fork())) break; while (wait(0) != child) if (INET_SERVER_start) { n = 0; // reset error counter on "real" signal break; } gds__log("INET_SERVER/main: gds_inet_server restarted"); } #ifdef UNIX set_signal(SIGUSR1, SIG_DFL); #endif } #endif if (standalone) { if (multi_client) { #ifdef SUPERSERVER // Remove restriction on username, for DEV builds // restrict only for production builds. MOD 21-July-2002 #ifndef DEV_BUILD Firebird::string user_name; // holds the user name // check user id ISC_get_user(&user_name, NULL, NULL, NULL); if (user_name != "root" && user_name != FIREBIRD_USER_NAME && user_name != INTERBASE_USER_NAME && user_name != INTERBASE_USER_SHORT) { // invalid user -- bail out fprintf(stderr, "%s: Invalid user (must be %s, %s, %s or root).\n", "fbserver", FIREBIRD_USER_NAME, INTERBASE_USER_NAME, INTERBASE_USER_SHORT); exit(STARTUP_ERROR); } #endif #else if (setreuid(0, 0) < 0) printf("Inet_server: couldn't set uid to superuser.\n"); #endif INET_set_clients(clients); } if (!debug) { int mask = 0; // FD_ZERO(&mask); mask |= 1 << 2; // FD_SET(2, &mask); divorce_terminal(mask); } { // scope block ISC_STATUS_ARRAY status_vector; port = INET_connect(protocol, 0, status_vector, INET_SERVER_flag, 0); if (!port) { gds__print_status(status_vector); exit(STARTUP_ERROR); } } // end scope block } else { port = INET_server(channel); if (!port) { fprintf(stderr, "fbserver: Unable to start INET_server\n"); exit(STARTUP_ERROR); } } #ifdef SUPERSERVER // before starting the superserver stuff change directory to tmp if (CHANGE_DIR(TEMP_DIR)) { // error on changing the directory gds__log("Could not change directory to %s due to errno %d", TEMP_DIR, errno); } // Server tries to attach to security2.fdb to make sure everything is OK // This code fixes bug# 8429 + all other bug of that kind - from // now on the server exits if it cannot attach to the database // (wrong or no license, not enough memory, etc. { // scope TEXT path[MAXPATHLEN]; ISC_STATUS_ARRAY status; isc_db_handle db_handle = 0L; Jrd::SecurityDatabase::getPath(path); const char dpb[] = {isc_dpb_version1, isc_dpb_gsec_attach, 1, 1}; isc_attach_database(status, strlen(path), path, &db_handle, sizeof dpb, dpb); if (status[0] == 1 && status[1] > 0) { gds__log_status(path, status); isc_print_status(status); exit(STARTUP_ERROR); } isc_detach_database(status, &db_handle); if (status[0] == 1 && status[1] > 0) { gds__log_status(path, status); isc_print_status(status); exit(STARTUP_ERROR); } } // end scope shutdownInit(); #endif SRVR_multi_thread(port, INET_SERVER_flag); #ifdef DEBUG_GDS_ALLOC // In Debug mode - this will report all server-side memory leaks due to remote access //gds_alloc_report(0, __FILE__, __LINE__); Firebird::PathName name = fb_utils::getPrefix(fb_utils::FB_DIR_LOG, "memdebug.log"); FILE* file = fopen(name.c_str(), "w+t"); if (file) { fprintf(file, "Global memory pool allocated objects\n"); getDefaultMemoryPool()->print_contents(file); fclose(file); } #endif // perform atexit shutdown here when all globals in embedded library are active // also sync with possibly already running shutdown in dedicated thread fb_shutdown(10000, fb_shutrsn_exit_called); return FINI_OK; }
// The following two functions are temporary stubs and will be // removed as the services API takes shape. They are used to // test that the paths for starting services and parsing command-lines // are followed correctly. int test_thread(Firebird::UtilSvc* uSvc) { gds__log("Starting service"); return FINI_OK; }
int CLIB_ROUTINE main( int argc, char **argv) { /************************************** * * m a i n * ************************************** * * Functional description * If there is no command line, prompt for one, read it * and make an artificial argc/argv. Otherwise, pass * the specified argc/argv to IBMGR_exec_line (see below). * **************************************/ fprintf(stderr, "*** fbmgr is deprecated, will be removed soon ***\n"); gds__log("*** fbmgr is deprecated, will be removed soon ***"); // Let's see if we have something in environment variables Firebird::string user, password; fb_utils::readenv(ISC_USER, user); fb_utils::readenv(ISC_PASSWORD, password); Firebird::string host; // MMM - do not allow to change host now //fb_utils::readenv("ISC_HOST", host); TEXT msg[MSG_LEN]; // Let's get a real user name. This info is used by // START server command. Because server is not running // we can not check the password, thus we require a // real user to be root or FIREBIRD_USER_NAME or // INTERBASE_USER_NAME or INTERBASE_USER_SHORT const struct passwd* pw = getpwuid(getuid()); if (pw == NULL) { perror("getpwuid"); SRVRMGR_msg_get(MSG_GETPWFAIL, msg); fprintf(OUTFILE, "%s\n", msg); exit(FINI_ERROR); } strcpy(ibmgr_data.real_user, pw->pw_name); if (!strcmp(pw->pw_name, "root") || !strcmp(pw->pw_name, FIREBIRD_USER_NAME) || !strcmp(pw->pw_name, INTERBASE_USER_NAME) || !strcmp(pw->pw_name, INTERBASE_USER_SHORT)) { strcpy(ibmgr_data.user, SYSDBA_USER_NAME); } else copy_str_upper(ibmgr_data.user, pw->pw_name); if (user.length()) copy_str_upper(ibmgr_data.user, user.c_str()); if (password.length()) strcpy(ibmgr_data.password, password.c_str()); else ibmgr_data.password[0] = '\0'; if (host.length()) strcpy(ibmgr_data.host, host.c_str()); else strcpy(ibmgr_data.host, "localhost"); // Shutdown is not in progress and we are not attached to service yet. // But obviously we will need attachment. ibmgr_data.shutdown = false; ibmgr_data.attached = 0; ibmgr_data.reattach |= (REA_HOST | REA_USER | REA_PASSWORD); // No pidfile by default ibmgr_data.pidfile[0] = 0; // Special case a solitary -z switch. // Print the version and then drop into prompt mode. if (argc == 2 && *argv[1] == '-' && (argv[1][1] == 'Z' || argv[1][1] == 'z')) { parse_cmd_line(argc, argv, false); argc--; } SSHORT ret; if (argc > 1) { ret = parse_cmd_line(argc, argv, true); if (ret == FB_SUCCESS) { ret = SRVRMGR_exec_line(&ibmgr_data); if (ret) { SRVRMGR_msg_get(ret, msg); fprintf(OUTFILE, "%s\n", msg); } // We also need to check the shutdown flag here (if operation was // -shut -[noat|notr]) and, depending on what we want to do, either // wait here on some sort of a shutdown event, or go to the prompt mode SRVRMGR_cleanup(&ibmgr_data); exit(FINI_OK); } else if (ret != ACT_PROMPT) exit(FINI_OK); } int local_argc; SCHAR* local_argv[MAXARGS]; TEXT stuff[MAXSTUFF]; for (;;) { if (get_line(&local_argc, local_argv, stuff)) break; if (local_argc > 1) { ret = parse_cmd_line(local_argc, local_argv, false); if (ret == ACT_QUIT) break; if (ret == FB_SUCCESS) { ret = SRVRMGR_exec_line(&ibmgr_data); if (ret) { SRVRMGR_msg_get(ret, msg); fprintf(OUTFILE, "%s\n", msg); } } } } SRVRMGR_cleanup(&ibmgr_data); exit(FINI_OK); }
int CLIB_ROUTINE main( int argc, char** argv) { /************************************** * * m a i n * ************************************** * * Functional description * Run the server with apollo mailboxes. * **************************************/ try { RemPortPtr port; // We should support 3 modes: // 1. Standalone single-process listener (like SS). // 2. Standalone listener, forking on each packet accepted (look -s switch in CS). // 3. Process spawned by (x)inetd (like CS). bool classic = false; bool standaloneClassic = false; bool super = false; // It's very easy to detect that we are spawned - just check fd 0 to be a socket. const int channel = 0; struct stat stat0; if (fstat(channel, &stat0) == 0 && S_ISSOCK(stat0.st_mode)) { // classic server mode classic = true; } const TEXT* const* const end = argc + argv; argv++; bool debug = false; USHORT INET_SERVER_flag = 0; protocol[0] = 0; bool done = false; while (argv < end) { TEXT c; const TEXT* p = *argv++; if (*p++ == '-') { while (c = *p++) { switch (UPPER(c)) { case 'D': debug = true; break; case 'E': if (argv < end) { if (ISC_set_prefix(p, *argv) == -1) printf("Invalid argument Ignored\n"); else argv++; // do not skip next argument if this one is invalid } else { printf("Missing argument, switch -E ignored\n"); } done = true; break; case 'P': if (argv < end) { if (!classic) { fb_utils::snprintf(protocol, sizeof(protocol), "/%s", *argv++); } else { gds__log("Switch -P ignored in CS mode\n"); } } else { printf("Missing argument, switch -P ignored\n"); } break; case 'H': case '?': printf("Firebird TCP/IP server options are:\n"); printf(" -d : debug on\n"); printf(" -p <port> : specify port to listen on\n"); printf(" -z : print version and exit\n"); printf(" -h|? : print this help\n"); printf("\n"); printf(" (The following -e options used to be -h options)\n"); printf(" -e <firebird_root_dir> : set firebird_root path\n"); printf(" -el <firebird_lock_dir> : set runtime firebird_lock dir\n"); printf(" -em <firebird_msg_dir> : set firebird_msg dir path\n"); exit(FINI_OK); case 'Z': printf("Firebird TCP/IP server version %s\n", FB_VERSION); exit(FINI_OK); default: printf("Unknown switch '%c', ignored\n", c); break; } if (done) break; } } } if (Config::getServerMode() == MODE_CLASSIC) { if (!classic) standaloneClassic = true; } else { if (classic) { gds__log("Server misconfigured - to start it from (x)inetd add ServerMode=Classic to firebird.conf"); Firebird::Syslog::Record(Firebird::Syslog::Error, "Server misconfigured - add ServerMode=Classic to firebird.conf"); exit(STARTUP_ERROR); } INET_SERVER_flag |= SRVR_multi_client; super = true; } { // scope Firebird::MasterInterfacePtr master; master->serverMode(super ? 1 : 0); } if (debug) { INET_SERVER_flag |= SRVR_debug; } // activate paths set with -e family of switches ISC_set_prefix(0, 0); // ignore some signals set_signal(SIGPIPE, signal_handler); set_signal(SIGUSR1, signal_handler); set_signal(SIGUSR2, signal_handler); // First of all change directory to tmp if (chdir(TEMP_DIR)) { // error on changing the directory gds__log("Could not change directory to %s due to errno %d", TEMP_DIR, errno); } #ifdef FB_RAISE_LIMITS #ifdef RLIMIT_NPROC raiseLimit(RLIMIT_NPROC); #endif #if !(defined(DEV_BUILD)) if (Config::getBugcheckAbort()) #endif { // try to force core files creation raiseLimit(RLIMIT_CORE); } #if (defined SOLARIS || defined HPUX || defined LINUX) if (super) { // Increase max open files to hard limit for Unix // platforms which are known to have low soft limits. raiseLimit(RLIMIT_NOFILE); } #endif // Unix platforms #endif // FB_RAISE_LIMITS #ifdef HAVE_LOCALE_H // Pick up the system locale to allow SYSTEM<->UTF8 conversions inside the engine setlocale(LC_CTYPE, ""); #endif if (!(debug || classic)) { int mask = 0; // FD_ZERO(&mask); mask |= 1 << 2; // FD_SET(2, &mask); divorce_terminal(mask); } // check firebird.conf presence - must be for server if (Config::missFirebirdConf()) { Firebird::Syslog::Record(Firebird::Syslog::Error, "Missing master config file firebird.conf"); exit(STARTUP_ERROR); } if (super || standaloneClassic) { try { port = INET_connect(protocol, 0, INET_SERVER_flag, 0, NULL); } catch (const Firebird::Exception& ex) { iscLogException("startup:INET_connect:", ex); Firebird::StaticStatusVector st; ex.stuffException(st); gds__print_status(st.begin()); exit(STARTUP_ERROR); } } if (classic) { port = INET_server(channel); if (!port) { gds__log("Unable to start INET_server"); Firebird::Syslog::Record(Firebird::Syslog::Error, "Unable to start INET_server"); exit(STARTUP_ERROR); } } { // scope for interface ptr Firebird::PluginManagerInterfacePtr pi; Auth::registerSrpServer(pi); } if (super) { // Server tries to attach to security2.fdb to make sure everything is OK // This code fixes bug# 8429 + all other bug of that kind - from // now on the server exits if it cannot attach to the database // (wrong or no license, not enough memory, etc. ISC_STATUS_ARRAY status; isc_db_handle db_handle = 0L; const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig()); const char* path = defConf->getSecurityDatabase(); const char dpb[] = {isc_dpb_version1, isc_dpb_sec_attach, 1, 1, isc_dpb_address_path, 0}; isc_attach_database(status, strlen(path), path, &db_handle, sizeof dpb, dpb); if (status[0] == 1 && status[1] > 0) { logSecurityDatabaseError(path, status); } isc_detach_database(status, &db_handle); if (status[0] == 1 && status[1] > 0) { logSecurityDatabaseError(path, status); } } // end scope fb_shutdown_callback(NULL, closePort, fb_shut_exit, port); SRVR_multi_thread(port, INET_SERVER_flag); #ifdef DEBUG_GDS_ALLOC // In Debug mode - this will report all server-side memory leaks due to remote access Firebird::PathName name = fb_utils::getPrefix( Firebird::IConfigManager::DIR_LOG, "memdebug.log"); FILE* file = os_utils::fopen(name.c_str(), "w+t"); if (file) { fprintf(file, "Global memory pool allocated objects\n"); getDefaultMemoryPool()->print_contents(file); fclose(file); } #endif // perform atexit shutdown here when all globals in embedded library are active // also sync with possibly already running shutdown in dedicated thread fb_shutdown(10000, fb_shutrsn_exit_called); return FINI_OK; } catch (const Firebird::Exception& ex) { Firebird::StaticStatusVector st; ex.stuffException(st); char s[100]; const ISC_STATUS* status = st.begin(); fb_interpret(s, sizeof(s), &status); iscLogException("Firebird startup error:", ex); Firebird::Syslog::Record(Firebird::Syslog::Error, "Firebird startup error"); Firebird::Syslog::Record(Firebird::Syslog::Error, s); exit(STARTUP_ERROR); } }
bool IntlUtil::initUnicodeCollation(texttype* tt, charset* cs, const ASCII* name, USHORT attributes, const UCharBuffer& specificAttributes, const string& configInfo) { memset(tt, 0, sizeof(*tt)); // name comes from stack. Copy it. ASCII* nameCopy = FB_NEW ASCII[strlen(name) + 1]; strcpy(nameCopy, name); tt->texttype_name = nameCopy; tt->texttype_version = TEXTTYPE_VERSION_1; tt->texttype_country = CC_INTL; tt->texttype_canonical_width = 4; // UTF-32 tt->texttype_fn_destroy = unicodeDestroy; tt->texttype_fn_compare = unicodeCompare; tt->texttype_fn_key_length = unicodeKeyLength; tt->texttype_fn_string_to_key = unicodeStrToKey; tt->texttype_fn_canonical = unicodeCanonical; IntlUtil::SpecificAttributesMap map; Jrd::CharSet* charSet = NULL; try { charSet = Jrd::CharSet::createInstance(*getDefaultMemoryPool(), 0, cs); IntlUtil::parseSpecificAttributes(charSet, specificAttributes.getCount(), specificAttributes.begin(), &map); delete charSet; } catch (...) { delete charSet; gds__log("initUnicodeCollation failed - unexpected exception caught"); return false; } IntlUtil::SpecificAttributesMap map16; SpecificAttributesMap::Accessor accessor(&map); bool found = accessor.getFirst(); while (found) { UCharBuffer s1, s2; USHORT errCode; ULONG errPosition; s1.resize(cs->charset_to_unicode.csconvert_fn_convert( &cs->charset_to_unicode, accessor.current()->first.length(), NULL, 0, NULL, &errCode, &errPosition)); s1.resize(cs->charset_to_unicode.csconvert_fn_convert( &cs->charset_to_unicode, accessor.current()->first.length(), (UCHAR*) accessor.current()->first.c_str(), s1.getCapacity(), s1.begin(), &errCode, &errPosition)); s2.resize(cs->charset_to_unicode.csconvert_fn_convert( &cs->charset_to_unicode, accessor.current()->second.length(), NULL, 0, NULL, &errCode, &errPosition)); s2.resize(cs->charset_to_unicode.csconvert_fn_convert( &cs->charset_to_unicode, accessor.current()->second.length(), (UCHAR*) accessor.current()->second.c_str(), s2.getCapacity(), s2.begin(), &errCode, &errPosition)); map16.put(string((char*) s1.begin(), s1.getCount()), string((char*) s2.begin(), s2.getCount())); found = accessor.getNext(); } UnicodeUtil::Utf16Collation* collation = UnicodeUtil::Utf16Collation::create(tt, attributes, map16, configInfo); if (!collation) { gds__log("initUnicodeCollation failed - UnicodeUtil::Utf16Collation::create failed"); return false; } tt->texttype_impl = FB_NEW TextTypeImpl(cs, collation); return true; }
void ConfigStorage::checkFile() { if (m_cfg_file >= 0) return; char* cfg_file_name = m_sharedMemory->getHeader()->cfg_file_name; if (!(*cfg_file_name)) { fb_assert(m_sharedMemory->getHeader()->cnt_uses == 0); char dir[MAXPATHLEN]; iscPrefixLock(dir, "", true); PathName filename = TempFile::create("fb_trace_", dir); filename.copyTo(cfg_file_name, sizeof(m_sharedMemory->getHeader()->cfg_file_name)); m_cfg_file = os_utils::openCreateSharedFile(cfg_file_name, O_BINARY); } else { m_cfg_file = ::open(cfg_file_name, O_RDWR | O_BINARY); if (m_cfg_file < 0) checkFileError(cfg_file_name, "open", isc_io_open_err); } // put default (audit) trace file contents into storage if (m_sharedMemory->getHeader()->change_number == 0) { FILE* cfgFile = NULL; try { PathName configFileName(Config::getAuditTraceConfigFile()); // remove quotes around path if present { // scope const FB_SIZE_T pathLen = configFileName.length(); if (pathLen > 1 && configFileName[0] == '"' && configFileName[pathLen - 1] == '"') { configFileName.erase(0, 1); configFileName.erase(pathLen - 2, 1); } } if (configFileName.empty()) return; if (PathUtils::isRelative(configFileName)) { PathName root(Config::getRootDirectory()); PathUtils::ensureSeparator(root); configFileName.insert(0, root); } cfgFile = fopen(configFileName.c_str(), "rb"); if (!cfgFile) { checkFileError(configFileName.c_str(), "fopen", isc_io_open_err); } TraceSession session(*getDefaultMemoryPool()); fseek(cfgFile, 0, SEEK_END); const long len = ftell(cfgFile); if (len) { fseek(cfgFile, 0, SEEK_SET); char* p = session.ses_config.getBuffer(len + 1); if (fread(p, 1, len, cfgFile) != size_t(len)) { checkFileError(configFileName.c_str(), "fread", isc_io_read_err); } p[len] = 0; } else { gds__log("Audit configuration file \"%s\" is empty", configFileName.c_str()); } session.ses_user = SYSDBA_USER_NAME; session.ses_name = "Firebird Audit"; session.ses_flags = trs_admin | trs_system; addSession(session); } catch(const Exception& ex) { ISC_STATUS_ARRAY temp; ex.stuff_exception(temp); iscLogStatus("Cannot open audit configuration file", temp); } if (cfgFile) { fclose(cfgFile); } } }
void DirectoryList::initialize(bool simple_mode) { if (mode != NotInitialized) return; clear(); PathName val = getConfigString(); if (simple_mode) { mode = SimpleList; } else { if (keyword(None, val, "None", "") || keyword(Full, val, "Full", "")) { return; } if (! keyword(Restrict, val, "Restrict", " \t")) { gds__log("DirectoryList: unknown parameter '%s', defaulting to None", val.c_str()); mode = None; return; } } size_t last = 0; PathName root = Config::getRootDirectory(); size_t i; for (i = 0; i < val.length(); i++) { if (val[i] == ';') { PathName dir = ""; if (i > last) { dir = val.substr(last, i - last); dir.trim(); } if (PathUtils::isRelative(dir)) { PathName newdir; PathUtils::concatPath(newdir, root, dir); dir = newdir; } add(ParsedPath(dir)); last = i + 1; } } PathName dir = ""; if (i > last) { dir = val.substr(last, i - last); dir.trim(); } if (PathUtils::isRelative(dir)) { PathName newdir; PathUtils::concatPath(newdir, root, dir); dir = newdir; } add(ParsedPath(dir)); }
void test_cmd(USHORT /*spb_length*/, SCHAR* /*spb*/, TEXT** /*switches*/) { gds__log("test_cmd called"); }
bool isGlobalKernelPrefix() { // The strategy of this function is as follows: use Global\ kernel namespace // for engine objects if we can. This can be prevented by either lack of OS support // for the feature (Win9X) or lack of privileges (Vista, Windows 2000/XP restricted accounts) const DWORD dwVersion = GetVersion(); // Is Windows NT running? if (!(dwVersion & 0x80000000)) { if (LOBYTE(LOWORD(dwVersion)) <= 4) // This is Windows NT 4.0 or earlier. return validateProductSuite("Terminal Server"); // Is it Windows 2000 or greater? It is possible to use Global\ prefix on any // version of Windows from Windows 2000 and up // Check if we have enough privileges to create global handles. // If not fall back to creating local ones. // The API for that is the NT thing, so we have to get addresses of the // functions dynamically to avoid troubles on Windows 9X platforms DynLibHandle hmodAdvApi(LoadLibrary("advapi32.dll")); if (!hmodAdvApi) { gds__log("LoadLibrary failed for advapi32.dll. Error code: %lu", GetLastError()); return false; } typedef BOOL (WINAPI *PFnOpenProcessToken) (HANDLE, DWORD, PHANDLE); typedef BOOL (WINAPI *PFnLookupPrivilegeValue) (LPCSTR, LPCSTR, PLUID); typedef BOOL (WINAPI *PFnPrivilegeCheck) (HANDLE, PPRIVILEGE_SET, LPBOOL); PFnOpenProcessToken pfnOpenProcessToken = (PFnOpenProcessToken) GetProcAddress(hmodAdvApi, "OpenProcessToken"); PFnLookupPrivilegeValue pfnLookupPrivilegeValue = (PFnLookupPrivilegeValue) GetProcAddress(hmodAdvApi, "LookupPrivilegeValueA"); PFnPrivilegeCheck pfnPrivilegeCheck = (PFnPrivilegeCheck) GetProcAddress(hmodAdvApi, "PrivilegeCheck"); if (!pfnOpenProcessToken || !pfnLookupPrivilegeValue || !pfnPrivilegeCheck) { // Should never happen, really gds__log("Cannot access privilege management API"); return false; } HANDLE hProcess = GetCurrentProcess(); HANDLE hToken; if (pfnOpenProcessToken(hProcess, TOKEN_QUERY, &hToken) == 0) { gds__log("OpenProcessToken failed. Error code: %lu", GetLastError()); return false; } PRIVILEGE_SET ps; memset(&ps, 0, sizeof(ps)); ps.Control = PRIVILEGE_SET_ALL_NECESSARY; ps.PrivilegeCount = 1; if (pfnLookupPrivilegeValue(NULL, TEXT("SeCreateGlobalPrivilege"), &ps.Privilege[0].Luid) == 0) { // Failure here means we're running on old version of Windows 2000 or XP // which always allow creating global handles CloseHandle(hToken); return true; } BOOL checkResult; if (pfnPrivilegeCheck(hToken, &ps, &checkResult) == 0) { gds__log("PrivilegeCheck failed. Error code: %lu", GetLastError()); CloseHandle(hToken); return false; } CloseHandle(hToken); return checkResult; } return false; }
int CLIB_ROUTINE main( int argc, char **argv) { /************************************** * * m a i n * ************************************** * * Functional description * The main for fbguard. This process is used to start * the standalone server and keep it running after an abnormal termination. * **************************************/ USHORT option = FOREVER; // holds FOREVER or ONETIME or IGNORE bool done = true; bool daemon = false; const TEXT* prog_name = argv[0]; const TEXT* pidfilename = 0; int guard_exit_code = 0; const TEXT* const* const end = argc + argv; argv++; while (argv < end) { const TEXT* p = *argv++; if (*p++ == '-') switch (UPPER(*p)) { case 'D': daemon = true; break; case 'F': option = FOREVER; break; case 'O': option = ONETIME; break; case 'S': option = IGNORE; break; case 'P': pidfilename = *argv++; break; default: fprintf(stderr, "Usage: %s [-signore | -onetime | -forever (default)] [-daemon] [-pidfile filename]\n", prog_name); exit(-1); break; } } // while // check user id Firebird::string user_name; // holds the user name ISC_get_user(&user_name, NULL, NULL, NULL); if (user_name != INTERBASE_USER && user_name != "root" && user_name != FIREBIRD_USER && user_name != INTERBASE_USER_SHORT) { // invalid user bail out fprintf(stderr, "%s: Invalid user (must be %s, %s, %s or root).\n", prog_name, FIREBIRD_USER, INTERBASE_USER, INTERBASE_USER_SHORT); exit(-2); } // get and set the umask for the current process const ULONG new_mask = 0007; const ULONG old_mask = umask(new_mask); // exclusive lock the file int fd_guard; if ((fd_guard = UTIL_ex_lock(GUARD_FILE)) < 0) { // could not get exclusive lock -- some other guardian is running if (fd_guard == -2) fprintf(stderr, "%s: Program is already running.\n", prog_name); exit(-3); } // the umask back to orignal donot want to carry this to child process umask(old_mask); // move the server name into the argument to be passed TEXT process_name[1024]; process_name[0] = '\0'; TEXT* server_args[2]; server_args[0] = process_name; server_args[1] = NULL; shutting_down = 0; if (UTIL_set_handler(SIGTERM, shutdown_handler, false) < 0) { fprintf(stderr, "%s: Cannot set signal handler (error %d).\n", prog_name, errno); exit(-5); } if (UTIL_set_handler(SIGINT, shutdown_handler, false) < 0) { fprintf(stderr, "%s: Cannot set signal handler (error %d).\n", prog_name, errno); exit(-5); } // detach from controlling tty if (daemon && fork()) { exit(0); } divorce_terminal(0); time_t timer = 0; do { int ret_code; if (shutting_down) { // don't start a child break; } if (timer == time(0)) { // don't let server restart too often - avoid log overflow sleep(1); continue; } timer = time(0); pid_t child_pid = UTIL_start_process(SUPER_SERVER_BINARY, SUPER_CLASSIC_BINARY, server_args, prog_name); if (child_pid == -1) { // could not fork the server gds__log("%s: guardian could not start server\n", prog_name/*, process_name*/); fprintf(stderr, "%s: Could not start server\n", prog_name/*, process_name*/); UTIL_ex_unlock(fd_guard); exit(-4); } if (pidfilename) { FILE *pf = fopen(pidfilename, "w"); if (pf) { fprintf(pf, "%d", child_pid); fclose(pf); } else { gds__log("%s: guardian could not open %s for writing, error %d\n", prog_name, pidfilename, errno); } } // wait for child to die, and evaluate exit status bool shutdown_child = true; if (!shutting_down) { ret_code = UTIL_wait_for_child(child_pid, shutting_down); shutdown_child = (ret_code == -2); } if (shutting_down) { if (shutdown_child) { ret_code = UTIL_shutdown_child(child_pid, 3, 1); if (ret_code < 0) { gds__log("%s: error while shutting down %s (%d)\n", prog_name, process_name, errno); guard_exit_code = -6; } else if (ret_code == 1) { gds__log("%s: %s killed (did not terminate)\n", prog_name, process_name); } else if (ret_code == 2) { gds__log("%s: unable to shutdown %s\n", prog_name, process_name); } else { gds__log("%s: %s terminated\n", prog_name, process_name); } } break; } if (ret_code != NORMAL_EXIT) { // check for startup error if (ret_code == STARTUP_ERROR) { gds__log("%s: %s terminated due to startup error (%d)\n", prog_name, process_name, ret_code); if (option == IGNORE) { gds__log("%s: %s terminated due to startup error (%d)\n Trying again\n", prog_name, process_name, ret_code); done = false; // Try it again, Sam (even if it is a startup error) FSG 8.11.2000 } else { gds__log("%s: %s terminated due to startup error (%d)\n", prog_name, process_name, ret_code); done = true; // do not restart we have a startup problem } } else { gds__log("%s: %s terminated abnormally (%d)\n", prog_name, process_name, ret_code); if (option == FOREVER || option == IGNORE) done = false; } } else { // Normal shutdown - don't restart the server gds__log("%s: %s normal shutdown.\n", prog_name, process_name); done = true; } } while (!done); if (pidfilename) { remove(pidfilename); } UTIL_ex_unlock(fd_guard); exit(guard_exit_code); } // main