Ejemplo n.º 1
0
/*
 * On Windows make sure that we are running with a restricted token,
 * On other platforms do nothing.
 */
void
get_restricted_token(const char *progname)
{
#ifdef WIN32
	HANDLE		restrictedToken;

	/*
	 * Before we execute another program, make sure that we are running with a
	 * restricted token. If not, re-execute ourselves with one.
	 */

	if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
		|| strcmp(restrict_env, "1") != 0)
	{
		PROCESS_INFORMATION pi;
		char	   *cmdline;

		ZeroMemory(&pi, sizeof(pi));

		cmdline = pg_strdup(GetCommandLine());

		putenv("PG_RESTRICT_EXEC=1");

		if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi, progname)) == 0)
		{
			fprintf(stderr, _("%s: could not re-execute with restricted token: error code %lu\n"), progname, GetLastError());
		}
		else
		{
			/*
			 * Successfully re-execed. Now wait for child process to capture
			 * exitcode.
			 */
			DWORD		x;

			CloseHandle(restrictedToken);
			CloseHandle(pi.hThread);
			WaitForSingleObject(pi.hProcess, INFINITE);

			if (!GetExitCodeProcess(pi.hProcess, &x))
			{
				fprintf(stderr, _("%s: could not get exit code from subprocess: error code %lu\n"), progname, GetLastError());
				exit(1);
			}
			exit(x);
		}
	}
#endif
}
Ejemplo n.º 2
0
/*
 * start command asynchronously.
 */
pid_t
forkexec(const char *cmd, int *outStdin)
{
	pid_t	pid;

	*outStdin = -1;

#ifndef WIN32
	{
		int		fd[2];

		if (pipe(fd) < 0 || (pid = fork()) < 0)
			return 0;

		if (pid == 0)
		{
			/* child process */
			if (close(fd[1]) < 0 || dup2(fd[0], STDIN_FILENO) < 0 ||
				execl("/bin/sh", "sh", "-c", cmd, NULL) < 0)
			{
				elog(LOG, "pg_statsinfo(): could not execute background process: %s",
					 strerror(errno));
				exit(1);
			}
		}

		close(fd[0]);
		*outStdin = fd[1];
	}
#else
	{
		PROCESS_INFORMATION pi;

		*outStdin = CreateRestrictedProcess((char *) cmd, &pi, false);
		if (*outStdin)
			pid = (pid_t) pi.dwProcessId;
		else
		{
			_dosmaperr(GetLastError());
			pid = 0;
		}
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}
#endif

	return pid;
}
static int
start_postmaster(void)
{
	char		cmd[MAXPGPATH];

#ifndef WIN32

	/*
	 * Since there might be quotes to handle here, it is easier simply to pass
	 * everything to a shell to process them.
	 */
	if (log_file != NULL)
		snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &" SYSTEMQUOTE,
				 exec_path, pgdata_opt, post_opts,
				 DEVNULL, log_file);
	else
		snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" 2>&1 &" SYSTEMQUOTE,
				 exec_path, pgdata_opt, post_opts, DEVNULL);

	return system(cmd);
#else							/* WIN32 */

	/*
	 * On win32 we don't use system(). So we don't need to use & (which would
	 * be START /B on win32). However, we still call the shell (CMD.EXE) with
	 * it to handle redirection etc.
	 */
	PROCESS_INFORMATION pi;

	if (log_file != NULL)
		snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE,
				 exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
	else
		snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE "\"%s\" %s%s < \"%s\" 2>&1" SYSTEMQUOTE,
				 exec_path, pgdata_opt, post_opts, DEVNULL);

	if (!CreateRestrictedProcess(cmd, &pi, false))
		return GetLastError();
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	return 0;
#endif   /* WIN32 */
}
Ejemplo n.º 4
0
int
main(int argc, char *argv[])
{
	/*
	 * options with no short version return a low integer, the rest return
	 * their short version value
	 */
	static struct option long_options[] = {
		{"pgdata", required_argument, NULL, 'D'},
		{"help", no_argument, NULL, '?'},
		{"version", no_argument, NULL, 'V'},
		{"debug", no_argument, NULL, 'd'},
		{"show", no_argument, NULL, 's'},
		{"noclean", no_argument, NULL, 'n'},
		{NULL, 0, NULL, 0}
	};

	int			c, ret;
	int			option_index;
	char	   *effective_user;
	char		bin_dir[MAXPGPATH];
	char	   *pg_data_native;
	bool		node_type_specified = false;

	progname = get_progname(argv[0]);
	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("initgtm"));

	if (argc > 1)
	{
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
		{
		usage(progname);
			exit(0);
		}
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
		{
			puts("initgtm (Postgres-XL) " PGXC_VERSION);
			exit(0);
		}
	}

	/* process command-line options */

	while ((c = getopt_long(argc, argv, "dD:nsZ:", long_options, &option_index)) != -1)
	{
		switch (c)
		{
			case 'D':
				pg_data = xstrdup(optarg);
				break;
			case 'd':
				debug = true;
				printf(_("Running in debug mode.\n"));
				break;
			case 'n':
				noclean = true;
				printf(_("Running in noclean mode.  Mistakes will not be cleaned up.\n"));
				break;
			case 's':
				show_setting = true;
				break;
			case 'Z':
				if (strcmp(xstrdup(optarg), "gtm") == 0)
					is_gtm = true;
				else if (strcmp(xstrdup(optarg), "gtm_proxy") == 0)
					is_gtm = false;
				else
				{
					fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
							progname);
					exit(1);
				}
				node_type_specified = true;
				break;
			default:
				/* getopt_long already emitted a complaint */
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
						progname);
				exit(1);
		}
	}

	/* Non-option argument specifies data directory */
	if (optind < argc)
	{
		pg_data = xstrdup(argv[optind]);
		optind++;
	}

	if (optind < argc)
	{
		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
				progname, argv[optind + 1]);
		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
				progname);
		exit(1);
	}

	/* Check on definition of GTM data folder */
	if (strlen(pg_data) == 0)
	{
		fprintf(stderr,
				_("%s: no data directory specified\n"
				  "You must identify the directory where the data for this GTM system\n"
				  "will reside.  Do this with either the invocation option -D or the\n"
				  "environment variable PGDATA.\n"),
				progname);
		exit(1);
	}

	if (!node_type_specified)
	{
		fprintf(stderr,
				_("%s: no node type specified\n"
				  "You must identify the node type chosen for initialization.\n"
				  "Do this with the invocation option -Z by choosing \"gtm\" or"
				  "\"gtm_proxy\"\n"),
				progname);
		exit(1);
	}

	pg_data_native = pg_data;
	canonicalize_path(pg_data);

#ifdef WIN32

	/*
	 * Before we execute another program, make sure that we are running with a
	 * restricted token. If not, re-execute ourselves with one.
	 */

	if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
		|| strcmp(restrict_env, "1") != 0)
	{
		PROCESS_INFORMATION pi;
		char	   *cmdline;

		ZeroMemory(&pi, sizeof(pi));

		cmdline = xstrdup(GetCommandLine());

		putenv("PG_RESTRICT_EXEC=1");

		if (!CreateRestrictedProcess(cmdline, &pi))
		{
			fprintf(stderr, "Failed to re-exec with restricted token: %lu.\n", GetLastError());
		}
		else
		{
			/*
			 * Successfully re-execed. Now wait for child process to capture
			 * exitcode.
			 */
			DWORD		x;

			CloseHandle(pi.hThread);
			WaitForSingleObject(pi.hProcess, INFINITE);

			if (!GetExitCodeProcess(pi.hProcess, &x))
			{
				fprintf(stderr, "Failed to get exit code from subprocess: %lu\n", GetLastError());
				exit(1);
			}
			exit(x);
		}
	}
#endif

	/* Like for initdb, check if a valid version of Postgres is running */
	if ((ret = find_other_exec(argv[0], "postgres", PG_BACKEND_VERSIONSTR,
							   backend_exec)) < 0)
	{
		char        full_path[MAXPGPATH];

		if (find_my_exec(argv[0], full_path) < 0)
			strlcpy(full_path, progname, sizeof(full_path));

		if (ret == -1)
			fprintf(stderr,
					_("The program \"postgres\" is needed by %s "
					  "but was not found in the\n"
					  "same directory as \"%s\".\n"
					  "Check your installation.\n"),
					progname, full_path);
		else
			fprintf(stderr,
					_("The program \"postgres\" was found by \"%s\"\n"
					  "but was not the same version as %s.\n"
					  "Check your installation.\n"),
					full_path, progname);
		exit(1);
	}

	/* store binary directory */
	strcpy(bin_path, backend_exec);
	*last_dir_separator(bin_path) = '\0';
	canonicalize_path(bin_path);

	if (!share_path)
	{
		share_path = pg_malloc(MAXPGPATH);
		get_share_path(backend_exec, share_path);
	}
	else if (!is_absolute_path(share_path))
	{
		fprintf(stderr, _("%s: input file location must be an absolute path\n"), progname);
		exit(1);
	}

	canonicalize_path(share_path);

	effective_user = get_id();

	/* Take into account GTM and GTM-proxy cases */
	if (is_gtm)
		set_input(&conf_file, "gtm.conf.sample");
	else
		set_input(&conf_file, "gtm_proxy.conf.sample");

	if (show_setting || debug)
	{
		fprintf(stderr,
				"VERSION=%s\n"
				"GTMDATA=%s\nshare_path=%s\nGTMPATH=%s\n"
				"GTM_CONF_SAMPLE=%s\n",
				PGXC_VERSION,
				pg_data, share_path, bin_path,
				conf_file);
		if (show_setting)
			exit(0);
	}

	check_input(conf_file);

	printf(_("The files belonging to this GTM system will be owned "
			 "by user \"%s\".\n"
			 "This user must also own the server process.\n\n"),
		   effective_user);

	printf("\n");

	umask(S_IRWXG | S_IRWXO);

	/*
	 * now we are starting to do real work, trap signals so we can clean up
	 */

	/* some of these are not valid on Windows */
#ifdef SIGHUP
	pqsignal(SIGHUP, trapsig);
#endif
#ifdef SIGINT
	pqsignal(SIGINT, trapsig);
#endif
#ifdef SIGQUIT
	pqsignal(SIGQUIT, trapsig);
#endif
#ifdef SIGTERM
	pqsignal(SIGTERM, trapsig);
#endif

	/* Ignore SIGPIPE when writing to backend, so we can clean up */
#ifdef SIGPIPE
	pqsignal(SIGPIPE, SIG_IGN);
#endif

	switch (pg_check_dir(pg_data))
	{
		case 0:
			/* PGDATA not there, must create it */
			printf(_("creating directory %s ... "),
				   pg_data);
			fflush(stdout);

			if (!mkdatadir(NULL))
				exit_nicely();
			else
				check_ok();

			made_new_pgdata = true;
			break;

		case 1:
			/* Present but empty, fix permissions and use it */
			printf(_("fixing permissions on existing directory %s ... "),
				   pg_data);
			fflush(stdout);

			if (chmod(pg_data, S_IRWXU) != 0)
			{
				fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
						progname, pg_data, strerror(errno));
				exit_nicely();
			}
			else
				check_ok();

			found_existing_pgdata = true;
			break;

		case 2:
			/* Present and not empty */
			fprintf(stderr,
					_("%s: directory \"%s\" exists but is not empty\n"),
					progname, pg_data);
			fprintf(stderr,
					_("If you want to create a new GTM system, either remove or empty\n"
					  "the directory \"%s\" or run %s\n"
					  "with an argument other than \"%s\".\n"),
					pg_data, progname, pg_data);
			exit(1);			/* no further message needed */

		default:
			/* Trouble accessing directory */
			fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
					progname, pg_data, strerror(errno));
			exit_nicely();
	}

	/* Select suitable configuration settings */
	set_null_conf();

	/* Now create all the text config files */
	setup_config();

	/* Get directory specification used to start this executable */
	strcpy(bin_dir, argv[0]);
	get_parent_directory(bin_dir);

	if (is_gtm)
		printf(_("\nSuccess. You can now start the GTM server using:\n\n"
				 "    %s%s%sgtm%s -D %s%s%s\n"
				 "or\n"
				 "    %s%s%sgtm_ctl%s -Z gtm -D %s%s%s -l logfile start\n\n"),
		   QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
			   QUOTE_PATH, pg_data_native, QUOTE_PATH,
		   QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
			   QUOTE_PATH, pg_data_native, QUOTE_PATH);
	else
		printf(_("\nSuccess. You can now start the GTM proxy server using:\n\n"
				 "    %s%s%sgtm_proxy%s -D %s%s%s\n"
				 "or\n"
				 "    %s%s%sgtm_ctl%s -Z gtm_proxy -D %s%s%s -l logfile start\n\n"),
		   QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
			   QUOTE_PATH, pg_data_native, QUOTE_PATH,
		   QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
			   QUOTE_PATH, pg_data_native, QUOTE_PATH);

	return 0;
}
static void WINAPI
pgwin32_ServiceMain(DWORD argc, LPTSTR *argv)
{
	PROCESS_INFORMATION pi;
	DWORD		ret;
	DWORD		check_point_start;

	/* Initialize variables */
	status.dwWin32ExitCode = S_OK;
	status.dwCheckPoint = 0;
	status.dwWaitHint = 60000;
	status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
	status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
	status.dwServiceSpecificExitCode = 0;
	status.dwCurrentState = SERVICE_START_PENDING;

	memset(&pi, 0, sizeof(pi));

	read_post_opts();

	/* Register the control request handler */
	if ((hStatus = RegisterServiceCtrlHandler(register_servicename, pgwin32_ServiceHandler)) == (SERVICE_STATUS_HANDLE) 0)
		return;

	if ((shutdownEvent = CreateEvent(NULL, true, false, NULL)) == NULL)
		return;

	/* Start the postmaster */
	pgwin32_SetServiceStatus(SERVICE_START_PENDING);
	if (!CreateRestrictedProcess(pgwin32_CommandLine(false), &pi, true))
	{
		pgwin32_SetServiceStatus(SERVICE_STOPPED);
		return;
	}
	postmasterPID = pi.dwProcessId;
	postmasterProcess = pi.hProcess;
	CloseHandle(pi.hThread);

	if (do_wait)
	{
		write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Waiting for server startup...\n"));
		if (test_postmaster_connection(true) == false)
		{
			write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Timed out waiting for server startup\n"));
			pgwin32_SetServiceStatus(SERVICE_STOPPED);
			return;
		}
		write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Server started and accepting connections\n"));
	}

	/*
	 * Save the checkpoint value as it might have been incremented in
	 * test_postmaster_connection
	 */
	check_point_start = status.dwCheckPoint;

	pgwin32_SetServiceStatus(SERVICE_RUNNING);

	/* Wait for quit... */
	ret = WaitForMultipleObjects(2, shutdownHandles, FALSE, INFINITE);

	pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
	switch (ret)
	{
		case WAIT_OBJECT_0:		/* shutdown event */
			kill(postmasterPID, SIGINT);

			/*
			 * Increment the checkpoint and try again Abort after 12
			 * checkpoints as the postmaster has probably hung
			 */
			while (WaitForSingleObject(postmasterProcess, 5000) == WAIT_TIMEOUT && status.dwCheckPoint < 12)
				status.dwCheckPoint++;
			break;

		case (WAIT_OBJECT_0 + 1):		/* postmaster went down */
			break;

		default:
			/* shouldn't get here? */
			break;
	}

	CloseHandle(shutdownEvent);
	CloseHandle(postmasterProcess);

	pgwin32_SetServiceStatus(SERVICE_STOPPED);
}