Translate

jeudi 16 avril 2015

UTL_FILE - ORA-06512 - ORA-29283


Il y a quelques jour un client m'est revenu avec un problème au moment de créer un fichier avec UTL_FILE, ci-dessous vous pouvez voir le script utilisé pour le test et le message d'erreur obtenu.
Version de Bd, 11.2.0.3 sous Solaris 5.10.


CONNECT COMPTEORACLE@MYBD

set serveroutput on ; 
declare
  fich utl_file.file_type;
begin
  fich := utl_file.fopen('REP_EVTA','monfichier.txt','W',32767);
  utl_file.put_line (fich,'Test');
  utl_file.fclose(fich);
  dbms_output.put_line ('Terminé');
 
exception
  when others then
    dbms_output.put_line ('Erreur : ' || sqlcode);
    dbms_output.put_line (substr(sqlerrm,1,200));
    utl_file.fclose_all;
end;
/

Erreur : -29283
ORA-29283: opération non valide sur le fichier
ORA-06512: à "SYS.UTL_FILE", ligne 536
ORA-29283: opération non valide sur le fichier


En regardant, il faut commencer par valider que l'utilisateur a vraiment les privilèges pour exécuter le UTL_FILE ou qu'au moins ils n'ont pas été révoqués du PUBLIC.

SELECT TABLE_NAME, PRIVILEGE, GRANTEE 
  FROM DBA_TAB_PRIVS 
 WHERE TABLE_NAME ='UTL_FILE' ;

TABLE_NAME       PRIVILEGE                        GRANTEE
---------------  -------------------------------- ----------------
UTL_FILE         EXECUTE                          PUBLIC
 
Jusqu'à ici tout est correct.

En suite, il faut valider que le compte "oracle" a les privilèges sur le répertoire "REP_EVTA"

SELECT TABLE_NAME, PRIVILEGE, GRANTEE 
  FROM DBA_TAB_PRIVS 
 WHERE GRANTEE= 'COMPTEORACLE' AND TABLE_NAME = 'EVTA' ;

TABLE_NAME        PRIVILEGE                 GRANTEE
----------------- ------------------------- --------------
REP_EVTA          EXECUTE                  
COMPTEORACLE 
REP_EVTA          READ                      COMPTEORACLE
REP_EVTA          WRITE                     COMPTEORACLE

Maintenant, validez si le répertoire physique existe et il est bel et bien accessible. Une recherche sur DBA_DIRECTORIES vous permettra de connaître le chemin du répertoire.

SELECT DIRECTORY_PATH 
  FROM DBA_DIRECTORIES 
 WHERE DIRECTORY_NAME='REP_EVTA' ;

DIRECTORY_PATH
--------------------------------------------------------
/chemin/sur/serveur/unix/repertoire


SQL> host ls -l /chemin/sur/serveur/unix/repertoire

-rw-rw-r--  1 2067     sql_group   13824 Oct  7  2014 fichier01.xls
-rw-rw-r--  1 2067    
sql_group   33871 Oct  2  2014 fichier02.csv
...


On voit que le répertoire est accessible et on peut même créer un fichier

SQL> host touch /chemin/sur/serveur/unix/repertoire/myfile.txt

SQL> host ls -l
/chemin/sur/serveur/unix/repertoire/myfile.txt
-rw-r--r-- 1 oracle oinstall 0 Apr 10 14:31
/chemin/.../repertoire/myfile.txt
 
Juste pour m'assurer, j'ai répété le même essai avec le compte "sys" mais sans passer par le Listener, soit directement avec un "sqlplus / as sysdba" et ma création a bien réussi cette fois.

      PL/SQL procedure successfully completed.

Pour vérifier, cette fois j'ai testé une autre fois avec "sys" mais en passant par le Listener, soit avec "sqlplus sys@MYDB as sysdba". Cette fois j'obtiens une autre fois l'erreur.

Erreur : -29283      
ORA-29283: opération non valide sur le fichier      
ORA-06512: à "SYS.UTL_FILE", ligne 536       
ORA-29283: opération non valide sur le fichier


C'est le moment d'aller regarder du côté OS et du "listener"


$ ps -ef | grep lsn | grep MYBD
 
grid 13777  1598 0  Jun 21 ? 190:23 /u01/.../bin/tnslsnr LSN_MYBD -inherit


Je vois qu'il a été reparti par le compte "grid", et cela peut expliquer le problème, pour vérifier, il faudrait regarder la définition du compte "grid"

$ id -a grid

uid=990(grid) gid=996(oinstall) groups=14(sysadmin),990(asmadmin),991(asmdba),992(asmoper),980(sql_group)


Si on remonte un niveau dans le répertoire

$ ls -l /chemin/sur/serveur/unix/

drwxrwx---   2 2067   sql_group   32K Apr 14 14:42 repertoire


Le répertoire appartient au même groupe, mais le "owner" est un compte qui n'existe pas sur le serveur.

$ is -a oracle
uid=991(oracle) gid=996(oinstall) groups=14(sysadmin)....980(sql_group)



Pour le compte "oracle"

$ umask
0022

Pour le compte "grid"

$ umask
0002


  • J'ai vérifié la dernière date où le listener a été reparti et il date d'il y a 3 mois, donc, pour m'assurer je repars le listener afin que le compte "grid" prenne en compte les groupes auquel il a été assigné. je modifié le umask avant de le repartie, mais malgré cela, je relance le test et même erreur.
  • En plus, j'ai pu constater que si je me connecte avec le compte "grid" et repars le listener avec "lsnrctl" et non pas avec "srvctl" -ce qu'on ne devrait pas faire mais qui a servi juste à mes tests-, le script est capable de créer le fichier. 

  • Donc, c'est clair que c'est un problème de privilèges.

À ce point-ci, on a deux possibles solutions :

  • Assigner comme "owner" du répertoire au compte propriétaire du processus "oracle", soit le configurer comme -idée suggérée par un collègue-. Bien sûr avec un chmod 777 au rpertoire avait démontré que cela fonctionnait mais cela serait moins sécurisant.
 drwxrwx---   2 oracle sql_group   32K Apr 14 14:42 repertoire


  • Suivre la note Oracle 1980622.1 qui demande un patch -qui existe seulement pour le moment pour Linux- et en plus de faire une modification au listener configuré auprès du srvctl
srvctl setenv listener -l LSN_MYBD -t ORA_RDBMS_UMASK=022

 Dans mon cas je ne peux pas appliquer ce patch parce que je suis sous Solaris. Donc la première alternative a aidé à corriger le problème.