Comment contourner MySQL Errcode 13 avec SELECT INTO OUTFILE?

114

J'essaie de vider le contenu d'une table dans un fichier csv en utilisant une instruction MySQL SELECT INTO OUTFILE. Si je fais:

SELECT column1, column2
INTO OUTFILE 'outfile.csv'
FIELDS TERMINATED BY ','
FROM table_name;

outfile.csv sera créé sur le serveur dans le même répertoire dans lequel les fichiers de cette base de données sont stockés.

Cependant, lorsque je change ma requête en:

SELECT column1, column2
INTO OUTFILE '/data/outfile.csv'
FIELDS TERMINATED BY ','
FROM table_name;

Je reçois:

ERROR 1 (HY000): Can't create/write to file '/data/outfile.csv' (Errcode: 13)

Errcode 13 est une erreur d'autorisations, mais je l'obtiens même si je change la propriété de / data en mysql: mysql et lui donne des autorisations 777. MySQL fonctionne en tant qu'utilisateur "mysql".

Étrangement, je peux créer le fichier dans / tmp, mais pas dans un autre répertoire que j'ai essayé, même avec des autorisations définies de sorte que l'utilisateur mysql puisse écrire dans le répertoire.

Il s'agit de MySQL 5.0.75 fonctionnant sous Ubuntu.

Ryan Olson
la source
3
Étant donné que le 13 est une erreur système, ce n'est probablement pas cela, mais il existe un paramètre mySQL limitant INTO OUTFILE à un répertoire: dev.mysql.com/doc/refman/5.0/en/ ... réglé sur /tmp.
Pekka
Cette variable est vide sur mon installation, ce qui, selon ce document, signifie que mes répertoires de sortie ne doivent pas être limités.
Ryan Olson

Réponses:

189

De quelle version particulière d'Ubuntu s'agit-il et s'agit-il d'Ubuntu Server Edition?

Les éditions récentes d'Ubuntu Server (telles que 10.04) fournies avec AppArmor et le profil de MySQL peuvent être en mode d'application par défaut. Vous pouvez vérifier cela en exécutant sudo aa-statuscomme suit:

# sudo aa-status
5 profiles are loaded.
5 profiles are in enforce mode.
   /usr/lib/connman/scripts/dhclient-script
   /sbin/dhclient3
   /usr/sbin/tcpdump
   /usr/lib/NetworkManager/nm-dhcp-client.action
   /usr/sbin/mysqld
0 profiles are in complain mode.
1 processes have profiles defined.
1 processes are in enforce mode :
   /usr/sbin/mysqld (1089)
0 processes are in complain mode.

Si mysqld est inclus en mode enforce, alors c'est probablement celui qui refuse l'écriture. Les entrées seraient également écrites /var/log/messageslorsque AppArmor bloque les écritures / accès. Ce que vous pouvez faire est de modifier /etc/apparmor.d/usr.sbin.mysqldet d'ajouter /data/et /data/*près du bas comme ceci:

...  
/usr/sbin/mysqld  {  
    ...  
    /var/log/mysql/ r,  
    /var/log/mysql/* rw,  
    /var/run/mysqld/mysqld.pid w,  
    /var/run/mysqld/mysqld.sock w,  
    **/data/ r,  
    /data/* rw,**  
}

Et puis faites AppArmor recharger les profils.

# sudo /etc/init.d/apparmor reload

AVERTISSEMENT: le changement ci-dessus permettra à MySQL de lire et d'écrire dans le répertoire / data. Nous espérons que vous avez déjà pris en compte les implications en matière de sécurité.

Vin-G
la source
2
Je déteste le signaler, mais il y a une raison pour laquelle App Armor ne le permet pas. MySQL a maintenant la possibilité de modifier et de lire tout ce qui se trouve dans le dossier / data. Ne vous faites pas pirater maintenant.
Ryan Ward
2
@Serdar, le jeu de règles AppArmor MySQL distribué avec la distribution ne le permet pas par défaut . Cela a du sens car c'est une bonne base de règles pour une nouvelle installation. Je pense que nous devrions et sommes autorisés à modifier les règles pour répondre à nos besoins après l'installation. L'intention initiale du demandeur était de permettre à MySQL d'écrire dans les répertoires spécifiques. Mais si ce n'est pas clairement explicite ci-dessus, une note pour les autres personnes qui trébuchent sur cette solution: ATTENTION: le changement ci-dessus permettra à MySQL de lire et d'écrire dans le répertoire / data. Nous espérons que vous avez déjà pris en compte les implications en matière de sécurité.
Vin-G
1
TRÈS BONNE RÉPONSE!!! Cela a résolu mon problème, j'essayais également d'écrire dans n'importe quel autre répertoire. Maintenant, je dois rechercher de quoi il s'agissait! :) En apprenant à ce sujet, je recommande à d'autres personnes de lire sur apparmor (et par conséquent, la commande aa-status): en.wikipedia.org/wiki/AppArmor
David L
1
Dans mon cas, cela a aidé: /your/abs/folder/ r, /your/abs/folder/** rwk, }n'oubliez pas d'inclure la virgule à la fin!
ACV
1
cela fonctionne pour écrire dans / tmp. Utilisez plutôt des fenêtres. Linux suce
Victor Ionescu
17

Ubuntu utilise AppArmor et c'est ce qui vous empêche d'accéder à / data /. Fedora utilise selinux et cela empêcherait cela sur une machine RHEL / Fedora / CentOS.

Pour modifier AppArmor pour permettre à MySQL d'accéder à / data /, procédez comme suit:

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

ajoutez cette ligne n'importe où dans la liste des répertoires:

/data/ rw,

puis faites un:

sudo /etc/init.d/apparmor restart

Une autre option consiste à désactiver complètement AppArmor pour mysql, ce n'est PAS RECOMMANDÉ :

sudo mv /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/

N'oubliez pas de redémarrer apparmor:

sudo /etc/init.d/apparmor restart

tour
la source
Pour désactiver réellement apparmor pour mysql, je devais faire: cyberciti.biz/faq/ubuntu-linux-howto-disable-apparmor-commands
silver_mx
14

Je sais que vous avez dit que vous avez déjà essayé de définir les autorisations sur 777, mais comme j'ai la preuve que pour moi, c'était un problème d'autorisation, je poste ce que je lance exactement en espérant que cela puisse aider. Voici mon expérience:

tmp $ pwd
/Users/username/tmp
tmp $ mkdir bkptest
tmp $ mysqldump -u root -T bkptest bkptest
mysqldump: Got error: 1: Can't create/write to file '/Users/username/tmp/bkptest/people.txt' (Errcode: 13) when executing 'SELECT INTO OUTFILE'
tmp $ chmod a+rwx bkptest/
tmp $ mysqldump -u root -T bkptest bkptest
tmp $ ls bkptest/
people.sql  people.txt
tmp $ 
basilikode
la source
me @ server: / data $ pwd / data me @ server: / data $ ls -al total 60 ... drwxrwxrwx 2 mysql mysql 4096 2010-05-06 16:27 dumptest me @ server: / data $ mysqldump -u dbuser -p -T dumptest -B nom_base --tables test Entrez le mot de passe: mysqldump: Erreur obtenue: 1: Impossible de créer / d'écrire dans le fichier '/data/dumptest/test.txt' (Errcode: 13) lors de l'exécution de 'SELECT INTO OUTFILE 'me @ server: / data $ sudo chmod a + rwx dumptest / me @ server: / data $ mysqldump -u dbuser -p -T dumptest -B db_name --tables test Entrez le mot de passe: mysqldump: Erreur obtenue: 1: ( même erreur)
Ryan Olson
Oy, eh bien, je ne savais pas que les commentaires ne se formateraient pas, mais j'ai vérifié de différentes manières. D'abord avec le répertoire cible appartenant à mysql: mysql, puis avec le répertoire cible appartenant à l'utilisateur sous lequel j'exécutais la commande dump, les deux méthodes me donnent toujours la même erreur d'autorisations.
Ryan Olson
Pour mémoire, cela a fonctionné pour moi malgré le changement des autorisations apparmor
Alex
J'ai essayé de modifier apparmor, cela n'a pas fonctionné. Changer l'autorisation 'chmod 777' a fonctionné pour moi!
Sudarshan_SMD
7

MySQL devient stupide ici. Il essaie de créer des fichiers sous / tmp / data / .... Donc ce que vous pouvez faire est ce qui suit:

mkdir /tmp/data
mount --bind /data /tmp/data

Ensuite, essayez votre requête. Cela a fonctionné pour moi après des heures de débogage du problème.

vimdude
la source
J'aime mieux cette réponse. C'est facile, cela fonctionne et cela ne vous oblige pas à utiliser Apparmor. L'autre façon de le faire en utilisant des tubes ne fonctionne pas bien pour les exportations importantes à cause de toute la mise en mémoire tampon qui est effectuée.
Chris Seline
6

Ce problème me dérange depuis longtemps. J'ai remarqué que cette discussion ne précise pas la solution sur RHEL / Fecora. J'utilise RHEL et je ne trouve pas les fichiers de configuration correspondant à AppArmer sur Ubuntu, mais j'ai résolu mon problème en rendant TOUS les répertoires du répertoire PATH lisibles et accessibles par mysql. Par exemple, si vous créez un répertoire / tmp, les deux commandes suivantes permettent à SELECT INTO OUTFILE de sortir le fichier .sql ET .sql

chown mysql:mysql /tmp
chmod a+rx /tmp

Si vous créez un répertoire dans votre répertoire personnel / home / tom, vous devez le faire pour / home et / home / tom.

fanchyna
la source
3
Utiliser / tmp comme exemple n'est pas une bonne idée, et vous ne voulez vraiment pas changer la propriété du répertoire / tmp (dans la plupart des cas).
sastorsl
Changer la propriété de / tmp est mauvais, mais créer un dossier temporaire dans / tmp et chown mysql:mysqlrésoudre mon problème
Samuel Prevost
6

Tu peux le faire :

mysql -u USERNAME --password=PASSWORD --database=DATABASE --execute='SELECT `FIELD`, `FIELD` FROM `TABLE` LIMIT 0, 10000 ' -X > file.xml
Navrattan Yadav
la source
Merci! Est-il possible de contrôler la sortie en CSV?
Hamman Samuel
4

Quelques choses à essayer:

  • la secure_file_privvariable système est-elle définie? Si tel est le cas, tous les fichiers doivent être écrits dans ce répertoire.
  • assurez-vous que le fichier n'existe pas - MySQL ne créera que de nouveaux fichiers et n'écrasera pas les fichiers existants.
mdma
la source
1
J'irais aussi pour secure_file_priv. Si le fichier existe déjà, le message d'erreur est différent (pas le code d'erreur 13).
Xavier Maillard
secure_file_priv n'est pas actuellement défini, donc si je comprends bien, cela signifie que je ne devrais pas être limité quant à l'endroit où je peux écrire des fichiers. Suis-je mal compris et dois-je le définir explicitement sur quelque chose comme «/» si je veux pouvoir écrire n'importe où sur le système de fichiers?
Ryan Olson le
De plus, je vérifie que le fichier n'existe pas avant d'exécuter la requête.
Ryan Olson le
Merci pour les commentaires. D'après vos conclusions, je ne pense pas que l'une ou l'autre de ces suggestions pose votre problème.
mdma le
3

J'ai le même problème et j'ai résolu ce problème en suivant les étapes:

  • Système d'exploitation: ubuntu 12.04
  • lampe installée
  • supposons que votre répertoire pour enregistrer le fichier de sortie soit: / var / www / csv /

Exécutez la commande suivante sur le terminal et modifiez ce fichier à l'aide de l'éditeur gedit pour ajouter votre répertoire au fichier de sortie.

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

  • maintenant le fichier serait ouvert dans l'éditeur, veuillez y ajouter votre répertoire

    / var / www / csv / * rw,

  • de même, j'ai ajouté dans mon fichier, comme suit l'image donnée:

entrez la description de l'image ici

Exécutez la commande suivante pour redémarrer les services:

sudo /etc/init.d/apparmor redémarrer

Par exemple, j'exécute la requête suivante dans le générateur de requêtes phpmyadmin pour générer des données dans un fichier csv

SELECT colName1, colName2,colName3
INTO OUTFILE '/var/www/csv/OUTFILE.csv'
FIELDS TERMINATED BY ','
FROM tableName;

Il a réussi et a écrit toutes les lignes avec les colonnes sélectionnées dans le fichier OUTPUT.csv ...

Sunny SM
la source
2

Dans mon cas, la solution était de rendre tous les répertoires du chemin d'accès lisibles et accessibles par mysql( chmod a+rx). Le répertoire était toujours spécifié par son chemin relatif dans la ligne de commande.

chmod a+rx /tmp
chmod a+rx /tmp/migration
etc.
Alsciende
la source
2

Je viens de rencontrer ce même problème. Mon problème était que le répertoire dans lequel j'essayais de vider n'avait pas l'autorisation d'écriture pour le processus mysqld. Le vidage SQL initial écrirait mais l'écriture du fichier csv / txt échouerait. On dirait que le vidage sql s'exécute en tant qu'utilisateur actuel et la conversion en csv / txt est exécutée en tant qu'utilisateur qui exécute mysqld. Le répertoire a donc besoin d'autorisations d'écriture pour les deux utilisateurs.

Matthew McMillan
la source
1

Vous devez fournir un chemin absolu, pas un chemin relatif.

Indiquez le chemin complet du répertoire / data dans lequel vous essayez d'écrire.

Ike Walker
la source
Cela me semble être un chemin absolu. N'est-ce pas?
Pekka
2
Essayez ceci en tant qu'utilisateur mysql pour vérifier que vous pouvez créer le fichier en dehors de mysql:touch /data/outfile.csv
Ike Walker
1
Premièrement, je ne pouvais pas le faire car le shell de l'utilisateur mysql était défini sur / bin / false, donc je ne pouvais pas me connecter en tant que mysql. Juste pour m'assurer que cela ne contribuait pas au problème, j'ai défini le shell de mysql sur / bin / bash, soumis à cet utilisateur et touché un fichier dans / data. Le fichier a été créé avec succès, propriété de mysql.
Ryan Olson
3
Vous pouvez poursuivre sur un compte même s'il utilise l'un des shells "désactiver": su --shell=/bin/sh nameofaccount
Marc B
Merci, je n'étais pas au courant de cela.
Ryan Olson
1

Ubuntu utilise-t-il SELinux? Vérifiez s'il est activé et en vigueur. /var/log/audit/audit.log peut être utile (si c'est là que Ubuntu le colle - c'est l'emplacement RHEL / Fedora).

Charles
la source
0

J'ai eu le même problème sur un CentOs 6.7 Dans mon cas, toutes les autorisations ont été définies et l'erreur s'est toujours produite. Le problème était que le SE Linux était dans le mode "enforcing".

Je l'ai commuté sur "permissif" en utilisant la commande sudo setenforce 0

Puis tout a fonctionné pour moi.

Stefan Bicher
la source