2010-05-26 4 views
2

EDIT: J'ai réécrit cette question, car je n'ai pas de réponse et j'essaie actuellement de réduire le problème.mysql UDF: fopen = permission refusée

J'essaye de créer un mysql UDF function vérifiant si un dossier existe du côté de serveur. Cette fonction appelle "ouvrir/fermer". Cela ne fonctionne pas même lorsque le fichier est lisible.

Je mets le code pour cette fonction ci-dessous:

#include <mysql.h> 
#include <string.h> 
#include <errno.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <fcntl.h> 

/* The initialization function */ 
my_bool fileExists_init(
     UDF_INIT *initid, 
     UDF_ARGS *args, 
     char *message 
     ) 
    { 
    /* check the args */ 
    if (!(args->arg_count == 1 && 
     args->arg_type[0] == STRING_RESULT 
     )) 
    { 
    strncpy(message,"Bad parameter expected a string",MYSQL_ERRMSG_SIZE); 
    return 1; 
    } 
    initid->maybe_null=1; 
    initid->ptr= NULL; 
    return 0; 
    } 

/* The deinitialization function */ 
void fileExists_deinit(UDF_INIT *initid) 
    { 
    } 

#define MAX_RESULT_LENGTH 250 
char *fileExists(
    UDF_INIT *initid, UDF_ARGS *args, char *result, 
    unsigned long *length, char *is_null, char *error) 
{ 
//bad filename 
if(args->args[0]==NULL || args->lengths[0]==0 || args->lengths[0] >= FILENAME_MAX) 
    { 
    strncpy(result,"#BAD_INPUT",MAX_RESULT_LENGTH); 
    } 
    else 
    { 
      char filename[FILENAME_MAX+1]; 
     int err; 
     int in; 
     //create a NULL terminated string 
     memcpy(filename,args->args[0],args->lengths[0]); 
     filename[args->lengths[0]]=0; 
     errno=0; 
     in=open(filename,O_RDONLY|O_NDELAY); 
     err=errno; 
     if(in<0) 
     { 
     snprintf(result,MAX_RESULT_LENGTH,"#ERR:\"%s\":\"%s\".",strerror(err),filename);  
     } 
     else 
     { 
     close(in); 
     snprintf(result,MAX_RESULT_LENGTH,"OK:\"%s\".",filename); 
     } 
    } 
    *length=strlen(result); 
    return result; 
    } 

Marque:

gcc -Wall -DMYSQL_VERSION -fPIC -shared `mysql_config --cflags` -o `mysql_config --plugindir`/libfileexists.so udffileexists.c `mysql_config --libs ` 

test:

ok, MySQL peut ouvrir des fichiers:

mysql> create function fileExists RETURNS STRING SONAME 'libfileexists.so'; select fileExists("/etc/mysql/my.cnf"); drop function fileExists; 
Query OK, 0 rows affected (0.00 sec) 

+---------------------------------+ 
| fileExists("/etc/mysql/my.cnf") | 
+---------------------------------+ 
| OK:"/etc/mysql/my.cnf".   | 
+---------------------------------+ 
1 row in set (0.00 sec) 



mysql> create function fileExists RETURNS STRING SONAME 'libfileexists.so'; select fileExists("/tmp/file.txt"); drop function fileExists; 
Query OK, 0 rows affected (0.00 sec) 

+-------------------------------+ 
| fileExists("/tmp/file.txt") | 
+-------------------------------+ 
| OK:"/tmp/file.txt".   | 
+-------------------------------+ 
1 row in set (0.00 sec) 

Query OK, 0 rows affected (0.00 sec) 

OK, pas de problème, ça marche s, je peux ouvrir() file.txt dans /tmp/

ls -la /tmp 
drwxrwxrwt 16 root root  4096 2010-05-28 15:45 . 
-rw-r--r-- 1 lindenb lindenb  0 2010-05-28 15:25 file.txt 

Mais quand je veux tester un fichier dans /données:

ls -la /data 
drwxrwxrwx 4 root root  4096 2010-05-28 16:11 . 
-rw-r--r-- 1 lindenb lindenb  0 2010-05-28 15:25 file.txt 

Je suis:

mysql> create function fileExists RETURNS STRING SONAME 'libfileexists.so'; select fileExists("/data/file.txt"); drop function fileExists; 
Query OK, 0 rows affected (0.00 sec) 

+--------------------------------------------+ 
| fileExists("/data/file.txt")    | 
+--------------------------------------------+ 
| #ERR:"Permission denied":"/data/file.txt". | 
+--------------------------------------------+ 
1 row in set (0.00 sec) 

Une idée?

Merci!

+1

open() renvoie -1 en cas d'erreur qui se trouve être -EACCESS (sur OS X au moins). Ce que vous voulez probablement, c'est strerror (errno).Pouvez-vous mettre à jour si cela rend l'erreur rapportée différente? –

+0

@Paul, c'est ce que j'ai vu: "strerror (err)" (j'ai tout d'abord rapidement copié errno pour errer car l'utilisation d'errno dans un programme MT est une mauvaise pratique). J'ai aussi essayé d'utiliser fopen plutôt qu'ouvert. cela donne le même type de résultat (in == NULL). Je cours sur mon localhost, ubuntu – Pierre

+0

Avez-vous essayé de su'ing à l'utilisateur exécutant MySQL pour vérifier qu'ils peuvent lire ce dossier? Vos autorisations semblent correctes à la lecture, mais c'est toujours une bonne vérification. –

Répondre

3

mysqld était protégé par apparmor.

AppArmor représente l'un de plusieurs approches possibles au problème de limitant les actions qui ont installé logiciel peut prendre.

I ajouté

/data/** r, 

à la fin de

/etc/apparmor.d/usr.sbin.mysqld 

AppArmor a été relancée:

/etc/init.d/apparmor restart 

et maintenant mon UDF fonctionne très bien! :-)

0

Pourquoi utilisez-vous le fichier ouvert? Il serait peut-être préférable de le faire de cette façon:

 
char *fileExists(
    UDF_INIT *initid, UDF_ARGS *args, char *result, 
    unsigned long *length, char *is_null, char *error) 
{ 
//bad filename 
if(args->args[0]==NULL || args->lengths[0]==0 || args->lengths[0] >= FILENAME_MAX) 
{ 
    strncpy(result,"#BAD_INPUT",MAX_RESULT_LENGTH); 
} 
else 
{ 
    char filename[FILENAME_MAX+1]; 
    int err; 
    int in; 
    struct stat statbuffer; 
    //create a NULL terminated string 
    memcpy(filename,args->args[0],args->lengths[0]); 
    filename[args->lengths[0]]=0; 
    errno=0; 
    if (!stat(filename, &statbuffer)){ 
    if (S_ISREG(statbuffer.st_mode)){ 
     snprintf(result,MAX_RESULT_LENGTH,"OK:\"%s\".",filename); 
    }else{ 
     snprintf(result,MAX_RESULT_LENGTH,"#ERR:\"%s\":\"%s\".",strerror(err),filename); 
    } 
    }else{ 
    snprintf(result,MAX_RESULT_LENGTH,"#ERR:\"%s\":\"%s\".",strerror(err),filename); 
    } 
} 
*length=strlen(result); 
return result; 
} 

Au lieu d'ouvrir le fichier, utilisez le stat, cela semble être le moyen fiable de vérifier si le fichier existe, et aussi, il serait plus facile pour savoir exactement pourquoi la fonction stat échouerait.

+0

J'ai utilisé fopen/open car mon premier fichier UDF d'origine doit lire le contenu du fichier. L'implémentation de 'fileExists' était juste un moyen d'affiner mon problème. Merci pour votre suggestion Je vais l'essayer demain, ça pourrait me donner quelques informations ... – Pierre

+0

Ok, j'ai testé cette solution aujourd'hui, "stat" dit "OK", les fichiers existent mais je n'arrive toujours pas à lire son contenu avec " ouvrir " – Pierre

Questions connexes