开发者

mysql UDF : fopen = permission denied

EDIT: I've re-written this question, as I got no answer and I'm currently trying to narrow the problem.

I'm trying to create a mysql UDF function checking if a file exists on the server side. This function calls "open/close". It doesn't work even when the file are readeable.

I put the code for this function below:

#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  file开发者_如何学CExists_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;
  }

Make:

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

Test:

ok, mysql can open some files:

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, no problem, it works, I can open() file.txt in /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

But when I want to test a file in /data:

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

I got:

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)

Any idea ?

Thanks !


mysqld was protected by apparmor.

AppArmor represents one of several possible approaches to the problem of restricting the actions that installed software can take.

I added

/data/** r,

at the end of

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

apparmor was restarted:

/etc/init.d/apparmor restart

and now my UDF works fine ! :-)


Why are you using the file open on it? Perhaps it might be better to do it this way:

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

Instead of opening the file, use the stat, this would seem to be the reliable way of checking if the file exists, and also, it would be easier to home in on exactly why would the stat function fail.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜