2010-05-26 248 views
2

编辑:我已经重新编写了这个问题,因为我没有答案,我正在努力缩小问题的范围。mysql UDF:fopen =权限被拒绝

我试图创建一个mysql UDF function检查服务器端是否存在文件。这个函数调用“打开/关闭”。即使文件可重新编译,它也不起作用。

我把代码下面这个函数:

#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; 
    } 

品牌:

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

测试:

OK,MySQL能够打开某些文件:

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) 

好的,没问题,它工作S,我可以在打开()file.txt的/ 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 

但是,当我想测试一个文件/数据

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 

我:

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) 

任何想法?

谢谢!

+1

open()返回-1,错误恰好是-EACCESS(至少在OS X上)。你可能想要的是strerror(errno)。你可以更新,如果这使得报告的错误不同? – 2010-05-28 15:09:37

+0

@Paul,这就是我所做的:“strerror(err)”(我首先很快将errno复制到错误,因为在MT程序中使用errno是一种不好的做法)。我也尝试过使用fopen而不是打开。它给出了相同的结果(在== NULL中)。我在我的本地主机上运行,​​ubuntu – Pierre 2010-05-28 15:37:21

+0

您是否尝试过使用运行MySQL的用户来验证他们是否可以读取该文件?您的权限看起来不错,但它总是一个很好的检查。 – 2010-05-28 15:43:06

回答

3

mysqld受apparmor保护。

的AppArmor代表的几个 可能的方法的 问题限制所安装 软件可以采取的行动之一。

我加

/data/** r, 

末的

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

AppArmor的重新启动:

/etc/init.d/apparmor restart 

,现在我的UDF正常工作! :-)

0

你为什么要使用打开的文件?也许它可能会更好做这种方式:

 
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; 
} 

而不是打开文件,使用stat,这似乎是检查文件是否存在的可靠方法,同时,它会更容易以确定为什么stat函数失败。

+0

我使用fopen/open,因为我的第一个原始UDF需要读取文件的内容。实施'fileExists'只是缩小我的问题的一种方法。谢谢你的建议明天我会试一下,它可能会给我一些信息... – Pierre 2010-05-31 15:50:49

+0

好的,我今天测试了这个解决方案,“stat”说“OK”,这些文件存在,但我仍然无法阅读它的内容, FOPEN” – Pierre 2010-06-01 10:46:49