Exemple #1
0
    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;
    }
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);
	}
}
Exemple #3
0
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