MySQL Forums
Forum List  »  Spanish

Re: Ejecutar aplicacion externa desde mysql
Posted by: Miguel Perez
Date: June 12, 2007 01:53AM

Quizás esto te pueda servir. Es una UDF de pruebas que estuve haciendo. Sirve para borrar archivos desde MySQL (es una interfaz a unlink). Elimina archivos siempre dentro de un directorio especificado y hardwireado en el código fuente, y no deja escapar a directorios de arriba con "..", con lo que hay que definir el directorio donde irán los archivos en el fuente de la función e incluso si comprometen MySQL no podrían utilizar esta función para hacer unlink fuera de ese directorio.

Esta función no está probada porque la he sacado de otro sistema que tenemos y para que te pudiera funcionar he tenido que hacerle alguna modificación, pero si no funciona inmediatamente, por lo menos será un buen punto de partida.


Este es el archivo fuente de la función en C:

--8<--------------------------------------------------
/****************************************************************************\
 * UDF FUNCTIONS FOR MYSQL                                                  *
 * Warning: This is highly experimental code. It was abandoned, and it has  *
 * been stripped of some functionality and it has not been properly tested. *
 *                                                                          *
 * This program provides User Defined Functions (UDFs) for MySQL 5 that     *
 * serve certain special purposes. Currently, the only function defined is  *
 * DeleteFile, which will delete files specified by their absolute name     *
 * inside UDF_BASE_DIRECTORY. Check the function doc for more information.  *
 * Functions defined here:                                                  *

	DeleteFile(filename) -> success
		Deletes a file within the configured UDF_BASE_DIRECTORY,
		returning 1 for successfully deleted files, 0 for files which were
		not found or unable to be deleted.

\****************************************************************************/

//Configuration: set the prefix for all file operations, can be a symlink
//Important: terminate it in a slash unless you know what you're doing.
#define UDF_BASE_DIRECTORY "/Software/Your_App/udfdir/"

//Configuration: define to forbid "." in names (note ".." is always forbidden)
#define UDF_NO_DOT_NAMES

/* 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 */

/* After compiling, define in MySQL like:
	CREATE FUNCTION DeleteFile RETURNS INT SONAME "udfs.so";
   You can undefine it like:
    DELETE FUNCTION DeleteFile;
*/

#ifdef STANDARD
/* STANDARD is defined, don't use any mysql functions */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef __WIN__
typedef unsigned __int64 ulonglong;	/* Microsofts 64 bit types */
typedef __int64 longlong;
#else
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif /*__WIN__*/
#else
#include <my_global.h>
#include <my_sys.h>
#if defined(MYSQL_SERVER)
#include <m_string.h>		/* To get strmov() */
#else
/* when compiled as standalone */
#define strmov(a,b) strcpy(a,b)
#define bzero(a,b) memset(a,0,b)
#define memcpy_fixed(a,b,c) memcpy(a,b,c)
#endif
#endif
#include <mysql.h>
#include <ctype.h>

static pthread_mutex_t LOCK_hostname;

#ifdef HAVE_DLOPEN





/* These must be right or mysqld will not find the symbol! */

my_bool DeleteFile_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
longlong DeleteFile(UDF_INIT *initid, UDF_ARGS *args, char *result,
	       unsigned long *length, char *is_null, char *error);
void DeleteFile_deinit(UDF_INIT *initid);




/*************************************************************************
** Example of init function
** Arguments:
** initid	Points to a structure that the init function should fill.
**		This argument is given to all other functions.
**	my_bool maybe_null	1 if function can return NULL
**				Default value is 1 if any of the arguments
**				is declared maybe_null.
**	unsigned int decimals	Number of decimals.
**				Default value is max decimals in any of the
**				arguments.
**	unsigned int max_length  Length of string result.
**				The default value for integer functions is 21
**				The default value for real functions is 13+
**				default number of decimals.
**				The default value for string functions is
**				the longest string argument.
**	char *ptr;		A pointer that the function can use.
**
** args		Points to a structure which contains:
**	unsigned int arg_count		Number of arguments
**	enum Item_result *arg_type	Types for each argument.
**					Types are STRING_RESULT, REAL_RESULT
**					and INT_RESULT.
**	char **args			Pointer to constant arguments.
**					Contains 0 for not constant argument.
**	unsigned long *lengths;		max string length for each argument
**	char *maybe_null		Information of which arguments
**					may be NULL
**
** message	Error message that should be passed to the user on fail.
**		The message buffer is MYSQL_ERRMSG_SIZE big, but one should
**		try to keep the error message less than 80 bytes long!
**
** This function should return 1 if something goes wrong. In this case
** message should contain something usefull!
**************************************************************************/
my_bool DeleteFile_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
	if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT) {
		strcpy(message, "UDF DeleteFile: usage: DeleteFile(filename) -> success");
    	return 1;
	}
	return 0;
}


/****************************************************************************
** Deinit function. This should free all resources allocated by
** this function.
** Arguments:
** initid	Return value from xxxx_init
****************************************************************************/
void DeleteFile_deinit(UDF_INIT *initid __attribute__((unused)))
{
}


/***************************************************************************
** UDF string function.
** Arguments:
** initid	Structure filled by xxx_init
** args		The same structure as to xxx_init. This structure
**		contains values for all parameters.
**		Note that the functions MUST check and convert all
**		to the type it wants!  Null values are represented by
**		a NULL pointer
** result	Possible buffer to save result. At least 255 byte long.
** length	Pointer to length of the above buffer.	In this the function
**		should save the result length
** is_null	If the result is null, one should store 1 here.
** error	If something goes fatally wrong one should store 1 here.
**
** This function should return a pointer to the result string.
** Normally this is 'result' but may also be an alloced string.
***************************************************************************/

#ifdef __WIN__
//Let's pray this works
#include <io.h>
#else
#include <unistd.h>
#endif

longlong DeleteFile(UDF_INIT *initid __attribute__((unused)),
  UDF_ARGS *args, char *result, unsigned long *length, char *is_null,
  char *error __attribute__((unused))) {

  	//Get the string passed as parameter into my own buffer, prefixed with the
  	//base directory, and ensure ASCIIZ.
  	char *src = args->args[0];
  	int srclen = args->lengths[0];

  	char *filename = malloc(strlen(UDF_BASE_DIRECTORY) + srclen + 1);
	char *dst = filename + strlen(UDF_BASE_DIRECTORY);

	//Copy prefix
	strcpy(filename, UDF_BASE_DIRECTORY);

	//Copy filename
	while (srclen-- > 0) {
		*dst++ = *src++;
	}
	*dst = 0; //Final 0

	//Security: check that there are no ".." or "."s in the name
#ifdef UDF_NO_DOT_NAMES
	//Check against "."
	if (strstr(filename, ".")) {
#else
	//Check against ".."
	if (strstr(filename, "..")) {
#endif
		free(filename);
		return 0;
	}

	//Delete file
	int retval = unlink(filename);

	free(filename);

	return retval == 0;
}




#endif /* HAVE_DLOPEN */
--8<--------------------------------------------------


Para compilarlo, puedes utilizar este script de sh (antes edita las variables a lo que sea apropiado y descomenta la línea de compilación para 32 o 64 bits según necesites):

--8<--------------------------------------------------
#!/bin/sh
#Run as root
#Requires sh - Windows users could try GNUWin32 or Cygwin

#Specify where's your mysql_config executable from your current MySQL server
#installation
CFG=/Software/mysql5/bin/mysql_config

#Specify your library directory: the directory where you want to install the
#library. For most machines, it'll be /usr/lib. For 64 bit Linuces running on
#AMD Athlon 64 and Opteron processors, it'll be /usr/lib64. For Windows, it
#simply can be the same directory as the mysqld executable.
LIBDIR=/usr/lib64

echo "Note: It's possible that you'll see several \"incompatible implicit declaration of built-in function\" warnings during compilation. This is ok."

#---FOR 32 BIT MACHINES---
#If your operating system doesn't use .so files, replace the extension by whatever you need
#gcc -m32 -O2 `$CFG --cflags` -shared -o udfs.so udfs.c

#---FOR 64 BIT MACHINES---
#If your operating system doesn't use .so files, replace the extension by whatever you need
gcc -m64 -fPIC -O2 `$CFG --cflags` -shared -o udfs.so udfs.c

mv udfs.so $LIBDIR/udfs.so
chown root:root $LIBDIR/udfs.so
chmod 755 $LIBDIR/udfs.so
--8<--------------------------------------------------


Suerte

Un saludo,

Miguel Pérez
Afina Sistemas - Partner de MySQL en España

Options: ReplyQuote


Subject
Views
Written By
Posted
Re: Ejecutar aplicacion externa desde mysql
3330
June 12, 2007 01:53AM


Sorry, you can't reply to this topic. It has been closed.

Content reproduced on this site is the property of the respective copyright holders. It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.