mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-30 04:26:45 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			478 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			478 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|   Copyright (c) 2003 Novell, Inc. All Rights Reserved. 
 | |
| 
 | |
|   This program is free software; you can redistribute it and/or modify 
 | |
|   it under the terms of the GNU General Public License as published by 
 | |
|   the Free Software Foundation; either version 2 of the License, or 
 | |
|   (at your option) any later version. 
 | |
| 
 | |
|   This program is distributed in the hope that it will be useful, 
 | |
|   but WITHOUT ANY WARRANTY; without even the implied warranty of 
 | |
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 | |
|   GNU General Public License for more details. 
 | |
| 
 | |
|   You should have received a copy of the GNU General Public License 
 | |
|   along with this program; if not, write to the Free Software 
 | |
|   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | |
| */ 
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <errno.h>
 | |
| #include <dirent.h>
 | |
| #include <string.h>
 | |
| #include <screen.h>
 | |
| #include <proc.h>
 | |
| #include <ctype.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <assert.h>
 | |
| 
 | |
| #include "my_manage.h"
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	macros
 | |
| 	
 | |
| ******************************************************************************/
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	global variables
 | |
| 	
 | |
| ******************************************************************************/
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	functions
 | |
| 	
 | |
| ******************************************************************************/
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	init_args()
 | |
| 	
 | |
| 	Init an argument list.
 | |
| 
 | |
| ******************************************************************************/
 | |
| void init_args(arg_list_t *al)
 | |
| {
 | |
|   ASSERT(al != NULL);
 | |
|   
 | |
|   al->argc = 0;
 | |
|   al->size = ARG_BUF;
 | |
|   al->argv = malloc(al->size * sizeof(char *));
 | |
|   ASSERT(al->argv != NULL);
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	add_arg()
 | |
| 	
 | |
| 	Add an argument to a list.
 | |
| 
 | |
| ******************************************************************************/
 | |
| void add_arg(arg_list_t *al, const char *format, ...)
 | |
| {
 | |
|   va_list ap;
 | |
|   char temp[PATH_MAX];
 | |
| 
 | |
|   ASSERT(al != NULL);
 | |
| 
 | |
|   // increase size
 | |
|   if (al->argc >= al->size)
 | |
|   {
 | |
|     al->size += ARG_BUF;
 | |
|     al->argv = realloc(al->argv, al->size * sizeof(char *));
 | |
|     ASSERT(al->argv != NULL);
 | |
|   }
 | |
| 
 | |
|   if (format)
 | |
|   {
 | |
|     va_start(ap, format);
 | |
|     vsprintf(temp, format, ap);
 | |
|     va_end(ap);
 | |
| 
 | |
|     al->argv[al->argc] = malloc(strlen(temp)+1);
 | |
|     ASSERT(al->argv[al->argc] != NULL);
 | |
|     strcpy(al->argv[al->argc], temp);
 | |
| 
 | |
|     ++(al->argc);
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     al->argv[al->argc] = NULL;
 | |
|   }
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	free_args()
 | |
| 	
 | |
| 	Free an argument list.
 | |
| 
 | |
| ******************************************************************************/
 | |
| void free_args(arg_list_t *al)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   ASSERT(al != NULL);
 | |
| 
 | |
|   for(i = 0; i < al->argc; i++)
 | |
|   {
 | |
|     ASSERT(al->argv[i] != NULL);
 | |
|     free(al->argv[i]);
 | |
|     al->argv[i] = NULL;
 | |
|   }
 | |
| 
 | |
|   free(al->argv);
 | |
|   al->argc = 0;
 | |
|   al->argv = NULL;
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	sleep_until_file_deleted()
 | |
| 	
 | |
| 	Sleep until the given file is no longer found.
 | |
| 
 | |
| ******************************************************************************/
 | |
| int sleep_until_file_deleted(char *pid_file)
 | |
| {
 | |
| 	struct stat buf;
 | |
| 	int i, err;
 | |
| 	
 | |
| 	for(i = 0; (i < TRY_MAX) && (err = !stat(pid_file, &buf)); i++) sleep(1);
 | |
| 	
 | |
| 	if (err != 0) err = errno;
 | |
| 	
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	sleep_until_file_exists()
 | |
| 
 | |
| 	Sleep until the given file exists.
 | |
| 
 | |
| ******************************************************************************/
 | |
| int sleep_until_file_exists(char *pid_file)
 | |
| {
 | |
| 	struct stat buf;
 | |
| 	int i, err;
 | |
| 	
 | |
| 	for(i = 0; (i < TRY_MAX) && (err = stat(pid_file, &buf)); i++) sleep(1);
 | |
| 	
 | |
| 	if (err != 0) err = errno;
 | |
| 	
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	wait_for_server_start()
 | |
| 	
 | |
| 	Wait for the server on the given port to start.
 | |
| 
 | |
| ******************************************************************************/
 | |
| int wait_for_server_start(char *bin_dir, char *user, char *password, int port,char *tmp_dir)
 | |
| {
 | |
|   arg_list_t al;
 | |
|   int err, i;
 | |
|   char mysqladmin_file[PATH_MAX];
 | |
|   char trash[PATH_MAX];
 | |
|   
 | |
| 	// mysqladmin file
 | |
|   snprintf(mysqladmin_file, PATH_MAX, "%s/mysqladmin", bin_dir);
 | |
|   snprintf(trash, PATH_MAX, "%s/trash.out",tmp_dir);
 | |
| 	
 | |
|   // args
 | |
|   init_args(&al);
 | |
|   add_arg(&al, "%s", mysqladmin_file);
 | |
|   add_arg(&al, "--no-defaults");
 | |
|   add_arg(&al, "--port=%u", port);
 | |
|   add_arg(&al, "--user=%s", user);
 | |
|   add_arg(&al, "--password=%s", password);
 | |
|   add_arg(&al, "--silent");
 | |
| 
 | |
| #ifdef NOT_USED
 | |
|   add_arg(&al, "-O");
 | |
|   add_arg(&al, "connect_timeout=10");
 | |
|   add_arg(&al, "-w");
 | |
| #endif
 | |
| 
 | |
|   add_arg(&al, "--host=localhost");
 | |
|   add_arg(&al, "ping");
 | |
| 
 | |
| 	// NetWare does not support the connect timeout in the TCP/IP stack
 | |
| 	// -- we will try the ping multiple times
 | |
| 	for(i = 0; (i < TRY_MAX)
 | |
|        && (err = spawn(mysqladmin_file, &al, TRUE, NULL,
 | |
|                        trash, NULL)); i++) sleep(1);
 | |
| 
 | |
|   // free args
 | |
|   free_args(&al);
 | |
| 
 | |
|   return err;
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	spawn()
 | |
| 	
 | |
| 	Spawn the given path with the given arguments.
 | |
| 
 | |
| ******************************************************************************/
 | |
| int spawn(char *path, arg_list_t *al, int join, char *input,
 | |
|           char *output, char *error)
 | |
| {
 | |
| 	pid_t pid;
 | |
|   int result = 0;
 | |
|   wiring_t wiring = { FD_UNUSED, FD_UNUSED, FD_UNUSED };
 | |
|   unsigned long flags = PROC_CURRENT_SPACE | PROC_INHERIT_CWD;
 | |
| 
 | |
|   // open wiring
 | |
|   if (input)
 | |
|     wiring.infd = open(input, O_RDONLY);
 | |
| 
 | |
|   if (output)
 | |
|     wiring.outfd = open(output, O_WRONLY | O_CREAT | O_TRUNC);
 | |
| 
 | |
|   if (error)
 | |
|     wiring.errfd = open(error, O_WRONLY | O_CREAT | O_TRUNC);
 | |
| 
 | |
|   // procve requires a NULL
 | |
|   add_arg(al, NULL);
 | |
| 
 | |
|   // go
 | |
|   pid = procve(path, flags, NULL, &wiring, NULL, NULL, 0,
 | |
|                NULL, (const char **)al->argv);
 | |
| 
 | |
| 	if (pid == -1)
 | |
|   {
 | |
|     result = -1;
 | |
|   }
 | |
|   else if (join)
 | |
|   {
 | |
|     waitpid(pid, &result, 0);
 | |
|   }
 | |
| 	
 | |
|   // close wiring
 | |
|   if (wiring.infd != -1)
 | |
|     close(wiring.infd);
 | |
| 
 | |
|   if (wiring.outfd != -1)
 | |
|     close(wiring.outfd);
 | |
| 
 | |
|   if (wiring.errfd != -1)
 | |
|     close(wiring.errfd);
 | |
| 
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	stop_server()
 | |
| 	
 | |
| 	Stop the server with the given port and pid file.
 | |
| 
 | |
| ******************************************************************************/
 | |
| int stop_server(char *bin_dir, char *user, char *password, int port,
 | |
|                 char *pid_file,char *tmp_dir)
 | |
| {
 | |
| 	arg_list_t al;
 | |
| 	int err, i, argc = 0;
 | |
|   char mysqladmin_file[PATH_MAX];
 | |
|   char trash[PATH_MAX];
 | |
|   
 | |
| 	// mysqladmin file
 | |
|   snprintf(mysqladmin_file, PATH_MAX, "%s/mysqladmin", bin_dir);
 | |
|   snprintf(trash, PATH_MAX, "%s/trash.out",tmp_dir);
 | |
| 	
 | |
|   // args
 | |
|   init_args(&al);
 | |
| 	add_arg(&al, "%s", mysqladmin_file);
 | |
| 	add_arg(&al, "--no-defaults");
 | |
| 	add_arg(&al, "--port=%u", port);
 | |
| 	add_arg(&al, "--user=%s", user);
 | |
| 	add_arg(&al, "--password=%s", password);
 | |
| 	add_arg(&al, "-O");
 | |
| 	add_arg(&al, "shutdown_timeout=20");
 | |
| 	add_arg(&al, "shutdown");
 | |
| 
 | |
| 	// spawn
 | |
| 	if ((err = spawn(mysqladmin_file, &al, TRUE, NULL,
 | |
|                    trash, NULL)) == 0)
 | |
| 	{
 | |
| 		sleep_until_file_deleted(pid_file);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
|     pid_t pid = get_server_pid(pid_file);
 | |
| 		
 | |
|     // shutdown failed - kill server
 | |
| 		kill_server(pid);
 | |
| 	
 | |
|   	sleep(TRY_MAX);
 | |
|     
 | |
|     // remove pid file if possible
 | |
|     err = remove(pid_file);
 | |
|   }
 | |
|   
 | |
|   // free args
 | |
|   free_args(&al);
 | |
| 
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	get_server_pid()
 | |
| 	
 | |
| 	Get the VM id with the given pid file.
 | |
| 
 | |
| ******************************************************************************/
 | |
| pid_t get_server_pid(char *pid_file)
 | |
| {
 | |
| 	char buf[PATH_MAX];
 | |
| 	int fd, err;
 | |
| 	char *p;
 | |
| 	pid_t id;
 | |
| 	
 | |
| 	// discover id
 | |
| 	fd = open(pid_file, O_RDONLY);
 | |
| 	
 | |
| 	err = read(fd, buf, PATH_MAX);
 | |
| 	
 | |
| 	close(fd);
 | |
| 	
 | |
| 	if (err > 0)
 | |
| 	{
 | |
| 		// terminate string
 | |
| 		if ((p = strchr(buf, '\n')) != NULL)
 | |
| 		{
 | |
| 			*p = NULL;
 | |
| 			
 | |
| 			// check for a '\r'
 | |
| 			if ((p = strchr(buf, '\r')) != NULL)
 | |
| 			{
 | |
| 				*p = NULL;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			buf[err] = NULL;
 | |
| 		}
 | |
| 		
 | |
| 		id = strtol(buf, NULL, 0);
 | |
| 	}
 | |
|   
 | |
|   return id;
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	kill_server()
 | |
| 	
 | |
| 	Force a kill of the server with the given pid.
 | |
| 
 | |
| ******************************************************************************/
 | |
| void kill_server(pid_t pid)
 | |
| {
 | |
|   if (pid > 0)
 | |
|   {
 | |
|     // destroy vm
 | |
|     NXVmDestroy(pid);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	del_tree()
 | |
| 	
 | |
| 	Delete the directory and subdirectories.
 | |
| 
 | |
| ******************************************************************************/
 | |
| void del_tree(char *dir)
 | |
| {
 | |
| 	DIR *parent = opendir(dir);
 | |
| 	DIR *entry;
 | |
| 	char temp[PATH_MAX];
 | |
| 	
 | |
| 	if (parent == NULL)
 | |
| 	{
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	while((entry = readdir(parent)) != NULL)
 | |
| 	{
 | |
| 		// create long name
 | |
| 		snprintf(temp, PATH_MAX, "%s/%s", dir, entry->d_name);
 | |
| 
 | |
| 		if (entry->d_name[0] == '.')
 | |
| 		{
 | |
| 			// Skip
 | |
| 		}
 | |
| 		else if (S_ISDIR(entry->d_type))
 | |
| 		{
 | |
| 			// delete subdirectory
 | |
| 			del_tree(temp);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			// remove file
 | |
| 			remove(temp);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// remove directory
 | |
| 	rmdir(dir);
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	removef()
 | |
| 	
 | |
| ******************************************************************************/
 | |
| int removef(const char *format, ...)
 | |
| {
 | |
| 	va_list ap;
 | |
|   char path[PATH_MAX];
 | |
| 	
 | |
| 	va_start(ap, format);
 | |
| 
 | |
| 	vsnprintf(path, PATH_MAX, format, ap);
 | |
| 	
 | |
| 	va_end(ap);
 | |
|   
 | |
|   return remove(path);
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
| 
 | |
| 	get_basedir()
 | |
| 	
 | |
| ******************************************************************************/
 | |
| void get_basedir(char *argv0, char *basedir)
 | |
| {
 | |
| 	char temp[PATH_MAX];
 | |
| 	char *p;
 | |
| 	
 | |
| 	ASSERT(argv0 != NULL);
 | |
|   ASSERT(basedir != NULL);
 | |
| 
 | |
| 	strcpy(temp, strlwr(argv0));
 | |
| 	while((p = strchr(temp, '\\')) != NULL) *p = '/';
 | |
| 	
 | |
| 	if ((p = strindex(temp, "/bin/")) != NULL)
 | |
| 	{
 | |
| 		*p = NULL;
 | |
| 		strcpy(basedir, temp);
 | |
| 	}
 | |
| }
 |