[Resolu] [C Linux] poser un verrou sur un fichier

poser un verrou sur un fichier [Resolu] [C Linux] - C - Programmation

Marsh Posté le 23-10-2006 à 19:07:51    

Bonjour les cracks.
 
J'ai crée un programme pour me familiariser avec les verrous.
Mon mode opératoire est le suivant, je crée et verrouille un fichier "socket.tmp" dans le repertoire /tmp, puis je mets le programme en pause (getchar).
J'ouvre ce fichier avec l'éditeur vim et je tente d'écrire dessus pour vérifier que le verrou soit bien installé. Or je peux écrire sans problème sur le fichier alors qu'il devrait être vérrouillé.
 
Si j'ouvre le fichier en lecture seulement, le fcntl() ne veut pas le verrouiller en écriture, ce qui me laisse supposer que fcntl() tente bien la pose de verrou.
La fonction is_locked_socket() censée vérifier que le verrou est présent rapporte dans tous les cas que le fichier n'est pas verrouillé !
 
=> J'en conclu que fcntl() démarre la pose du verrou mais cette dernière n'aboutie pas. fcntl() ne renvoit pourtant aucun message d'erreur.
 
main.c

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <socket.h>
  4. #include <unistd.h>
  5. const char test[3]="ab";
  6. int main ( int argc , char** argv )
  7. {
  8. int fd;
  9. chdir ( "/tmp" );
  10. if ( ( fd = open_socket ( "socket.tmp" ) ) < 0 )
  11. {
  12.  printf ( "Cannot create socket file\n" );
  13.  exit ( -1 );
  14. }
  15. printf ( "Press <RETURN> to set lock\n" );
  16. getchar ();
  17. if ( lock_socket ( fd ) < 0 )
  18. {
  19.  printf ( "Cannot lock socket file\n" );
  20.  exit ( -1 );
  21. }
  22. lseek ( fd , 0 , SEEK_END );
  23. write ( fd , &test[0] , 2 );
  24. printf ( "Press <RETURN> to remove lock\n" );
  25. getchar ();
  26. if ( unlock_socket ( fd ) < 0 )
  27.  exit ( -1 );
  28. if ( close_socket ( fd ) < 0 )
  29.  exit ( -1 );
  30. exit ( EXIT_SUCCESS );


 
socket.c

Code :
  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include "socket.h"
  6. #include <stdio.h>
  7. //--------------------------------------------------------------------
  8. /* Function Name      : open_socket
  9. * Object             : Opens an existing socket or creates it !
  10. * Input Parameters   : [char*] path = Name of the socket file.
  11. * Output Parameters  : [int] = File descriptor of the socket file.
  12. *     '-1' if error.
  13. * Functions called   : open(),lseek().
  14. */
  15. //--------------------------------------------------------------------
  16. int open_socket ( char* path )
  17. {
  18. int err, fd;
  19. /* OPEN the file */
  20. fd = open ( path , O_RDWR | O_CREAT,
  21.      S_IRUSR | S_IWUSR );
  22. if ( fd < 0 )
  23.  return SOCKET_ERROR;
  24. /* JUMP at the beginning of the file */
  25. err = lseek ( fd , 0 , SEEK_SET );
  26. if ( err < 0 )
  27.  return SOCKET_ERROR;
  28. return fd;
  29. }
  30. //--------------------------------------------------------------------
  31. /* Function Name      : close_socket
  32. * Object             : Close an existing socket.
  33. * Input Parameters   : [int] fd = File descriptor of the socket file.
  34. * Output Parameters  : [int] = exit status.
  35. *     '-1' if error.
  36. *     '0' if no error.
  37. * Functions called   : close().
  38. */
  39. int close_socket ( int fd )
  40. {
  41. return close ( fd );
  42. }
  43. //--------------------------------------------------------------------
  44. /* Function Name      : unlock_socket
  45. * Object             : Unlock an existing socket.
  46. * Input Parameters   : [int] fd = File descriptor of the socket file.
  47. * Output Parameters  : [int] = exit status.
  48. *     '-1' if error.
  49. *     '0' if no error.
  50. * Functions called   : fcntl().
  51. */
  52. //-------------------------------------------------------------------
  53. int unlock_socket ( int fd )
  54. {
  55. static struct flock lock;
  56. lock.l_type = F_UNLCK;
  57. lock.l_whence = SEEK_SET;
  58. lock.l_start = 0;
  59. lock.l_len = 0;
  60. return fcntl ( fd , F_SETLKW , &lock );
  61. }
  62. //--------------------------------------------------------------------
  63. /* Function Name      : lock_socket
  64. * Object             : Lock an existing socket.
  65. * Input Parameters   : [int] fd = File descriptor of the socket file.
  66. * Output Parameters  : [int] = exit status.
  67. *     '-1' if error.
  68. *     '0' if no error.
  69. * Functions called   : fcntl().
  70. */
  71. //-------------------------------------------------------------------
  72. int lock_socket ( int fd )
  73. {
  74. static struct flock lock;
  75. lock.l_type = F_WRLCK;
  76. lock.l_whence = SEEK_SET;
  77. lock.l_start = 0;
  78. lock.l_len = 0;
  79. return fcntl ( fd , F_SETLKW , &lock );
  80. }
  81. //--------------------------------------------------------------------
  82. /* Function Name      : is_locked_socket
  83. * Object             : Check if an existing socket is locked.
  84. * Input Parameters   : [int] fd = File descriptor of the socket file.
  85. * Output Parameters  : [int] = exit status.
  86. *     the pid of the process if locked.
  87. *     '0' if unlocked.
  88. *     '-1' if error;
  89. * Functions called   : fcntl().
  90. */
  91. //-------------------------------------------------------------------
  92. int is_locked_socket ( int fd )
  93. {
  94. static struct flock lock;
  95. lock.l_type = F_WRLCK;
  96. lock.l_whence = SEEK_SET;
  97. lock.l_start = 0;
  98. lock.l_len = 0;
  99. if ( fcntl ( fd , F_GETLK , &lock ) == -1 )
  100.  return -1;
  101. if ( lock.l_type == F_UNLCK )
  102.  return 0;
  103. else
  104.  return lock.l_pid;
  105. }

Message cité 1 fois
Message édité par escaflownn le 25-10-2006 à 15:46:37
Reply

Marsh Posté le 23-10-2006 à 19:07:51   

Reply

Marsh Posté le 24-10-2006 à 21:36:40    

J'ai du mal à croire que personne n'aie jamais posé de verrou Posix ici.

Reply

Marsh Posté le 25-10-2006 à 15:06:12    

escaflownn a écrit :

Bonjour les cracks.
 
J'ai crée un programme pour me familiariser avec les verrous.
Mon mode opératoire est le suivant, je crée et verrouille un fichier "socket.tmp" dans le repertoire /tmp, puis je mets le programme en pause (getchar).
J'ouvre ce fichier avec l'éditeur vim et je tente d'écrire dessus pour vérifier que le verrou soit bien installé. Or je peux écrire sans problème sur le fichier alors qu'il devrait être vérrouillé.
 
Si j'ouvre le fichier en lecture seulement, le fcntl() ne veut pas le verrouiller en écriture, ce qui me laisse supposer que fcntl() tente bien la pose de verrou.
La fonction is_locked_socket() censée vérifier que le verrou est présent rapporte dans tous les cas que le fichier n'est pas verrouillé !
 
=> J'en conclu que fcntl() démarre la pose du verrou mais cette dernière n'aboutie pas. fcntl() ne renvoit pourtant aucun message d'erreur.
 
main.c

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <socket.h>
  4. #include <unistd.h>
  5. const char test[3]="ab";
  6. int main ( int argc , char** argv )
  7. {
  8. int fd;
  9. chdir ( "/tmp" );
  10. if ( ( fd = open_socket ( "socket.tmp" ) ) < 0 )
  11. {
  12.  printf ( "Cannot create socket file\n" );
  13.  exit ( -1 );
  14. }
  15. printf ( "Press <RETURN> to set lock\n" );
  16. getchar ();
  17. if ( lock_socket ( fd ) < 0 )
  18. {
  19.  printf ( "Cannot lock socket file\n" );
  20.  exit ( -1 );
  21. }
  22. lseek ( fd , 0 , SEEK_END );
  23. write ( fd , &test[0] , 2 );
  24. printf ( "Press <RETURN> to remove lock\n" );
  25. getchar ();
  26. if ( unlock_socket ( fd ) < 0 )
  27.  exit ( -1 );
  28. if ( close_socket ( fd ) < 0 )
  29.  exit ( -1 );
  30. exit ( EXIT_SUCCESS );


 
socket.c

Code :
  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include "socket.h"
  6. #include <stdio.h>
  7. //--------------------------------------------------------------------
  8. /* Function Name      : open_socket
  9. * Object             : Opens an existing socket or creates it !
  10. * Input Parameters   : [char*] path = Name of the socket file.
  11. * Output Parameters  : [int] = File descriptor of the socket file.
  12. *     '-1' if error.
  13. * Functions called   : open(),lseek().
  14. */
  15. //--------------------------------------------------------------------
  16. int open_socket ( char* path )
  17. {
  18. int err, fd;
  19. /* OPEN the file */
  20. fd = open ( path , O_RDWR | O_CREAT,
  21.      S_IRUSR | S_IWUSR );
  22. if ( fd < 0 )
  23.  return SOCKET_ERROR;
  24. /* JUMP at the beginning of the file */
  25. err = lseek ( fd , 0 , SEEK_SET );
  26. if ( err < 0 )
  27.  return SOCKET_ERROR;
  28. return fd;
  29. }
  30. //--------------------------------------------------------------------
  31. /* Function Name      : close_socket
  32. * Object             : Close an existing socket.
  33. * Input Parameters   : [int] fd = File descriptor of the socket file.
  34. * Output Parameters  : [int] = exit status.
  35. *     '-1' if error.
  36. *     '0' if no error.
  37. * Functions called   : close().
  38. */
  39. int close_socket ( int fd )
  40. {
  41. return close ( fd );
  42. }
  43. //--------------------------------------------------------------------
  44. /* Function Name      : unlock_socket
  45. * Object             : Unlock an existing socket.
  46. * Input Parameters   : [int] fd = File descriptor of the socket file.
  47. * Output Parameters  : [int] = exit status.
  48. *     '-1' if error.
  49. *     '0' if no error.
  50. * Functions called   : fcntl().
  51. */
  52. //-------------------------------------------------------------------
  53. int unlock_socket ( int fd )
  54. {
  55. static struct flock lock;
  56. lock.l_type = F_UNLCK;
  57. lock.l_whence = SEEK_SET;
  58. lock.l_start = 0;
  59. lock.l_len = 0;
  60. return fcntl ( fd , F_SETLKW , &lock );
  61. }
  62. //--------------------------------------------------------------------
  63. /* Function Name      : lock_socket
  64. * Object             : Lock an existing socket.
  65. * Input Parameters   : [int] fd = File descriptor of the socket file.
  66. * Output Parameters  : [int] = exit status.
  67. *     '-1' if error.
  68. *     '0' if no error.
  69. * Functions called   : fcntl().
  70. */
  71. //-------------------------------------------------------------------
  72. int lock_socket ( int fd )
  73. {
  74. static struct flock lock;
  75. lock.l_type = F_WRLCK;
  76. lock.l_whence = SEEK_SET;
  77. lock.l_start = 0;
  78. lock.l_len = 0;
  79. return fcntl ( fd , F_SETLKW , &lock );
  80. }
  81. //--------------------------------------------------------------------
  82. /* Function Name      : is_locked_socket
  83. * Object             : Check if an existing socket is locked.
  84. * Input Parameters   : [int] fd = File descriptor of the socket file.
  85. * Output Parameters  : [int] = exit status.
  86. *     the pid of the process if locked.
  87. *     '0' if unlocked.
  88. *     '-1' if error;
  89. * Functions called   : fcntl().
  90. */
  91. //-------------------------------------------------------------------
  92. int is_locked_socket ( int fd )
  93. {
  94. static struct flock lock;
  95. lock.l_type = F_WRLCK;
  96. lock.l_whence = SEEK_SET;
  97. lock.l_start = 0;
  98. lock.l_len = 0;
  99. if ( fcntl ( fd , F_GETLK , &lock ) == -1 )
  100.  return -1;
  101. if ( lock.l_type == F_UNLCK )
  102.  return 0;
  103. else
  104.  return lock.l_pid;
  105. }



 
Désolé, j'ai pas le temps d'examiner ton code en détail. Je remarque quand-même que les fonctions "lock_socket" et "unlock_socket" sont quasiment les mêmes et pourraient être regroupées en une seule qui recevrait un paramètre supplémentaire "lock/unlock". Mais le pb ne vient pas de là.
Télécharge mon cours sur les processus http://fr.lang.free.fr/cours/Processus_Csyst_v1.0.pdf. Il y a un chapitre qui parle de la pose des verrous. Si j'ai un peu de temps, je reviendrai plus tard voir ce qui peut clocher...
 
Petit conseil: tu devrais utiliser de temps en temps "errno" ainsi que "perror()" histoire d'afficher ce que te dit le système quand ça cloche.
Autre remarque: Tes fonctions "lock/unlock" utilisent une structure statique ce qui signifie que la variable "lock" garde ses valeurs entre chaque appel. Si jamais un des membres de "lock" n'est pas réinitialisé alors qu'il le devrait, il gardera la valeur précédente et si celle-ci n'est pas bonne...
En général, une variable locale ne se met "static" que si on a un besoin impératif de garder sa valeur entre chaque appel (cas d'un compteur d'appels par exemple)...


Message édité par Sve@r le 25-10-2006 à 15:20:50

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 25-10-2006 à 15:46:24    

Merci pour tes précieux conseils, j'ai refondu le code en conséquence.
 
Concernant le problème, l'erreur venait du mode opératoire en deux points:
*tout d'abord vim ne tient pas compte des verrous, pour vérifier que le verrou est posé, il suffit en réalité d'éxécuter deux fois le processus en même temps.
*la fonction is_locked_socket() ne permet pas de vérifier à postériori si le processus a lui même posé un verrou, car un processus peut toujours poser un verrou à la place d'un verrou qu'il a lui même posé antèrieurement. C'est pour cette raison qu'elle renvoyait 0.
 
main.c

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <errno.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include "lock.h"
  9. int main ( int argc , char** argv )
  10. {
  11. int fd;
  12. char tab[4] = "ab\n";
  13. if ( chdir ( "/tmp" ) < 0 )
  14. {
  15.  perror ( "[main.c] chdir(0)" );
  16.  exit ( EXIT_FAILURE );
  17. }
  18. fd = open ( "fic_test.tmp" , O_RDWR | O_CREAT , S_IRWXU );
  19. if ( fd < 0 )
  20. {
  21.  perror ( "[main.c] open(0)" );
  22.  exit ( EXIT_FAILURE );
  23. }
  24. if ( lock_file ( fd , LOCK_NOWAIT ) < 0 )
  25. {
  26.  perror ( "[main.c] lock_file(0)" );
  27.  exit ( EXIT_FAILURE );
  28. }
  29. if ( lseek ( fd , 0 , SEEK_END ) < 0 )
  30. {
  31.  perror ( "[main.c] lseek(0)" );
  32.  exit ( EXIT_FAILURE );
  33. }
  34. printf ( "Press <RETURN> to continue\n" );
  35. getchar ( );
  36. if ( write ( fd , &tab[0] , 3 ) < 0 )
  37. {
  38.  perror ( "[main.c] write(0)" );
  39.  exit ( EXIT_FAILURE );
  40. }
  41. if ( lock_file ( fd , LOCK_UNLOCK ) < 0 )
  42. {
  43.  perror ( "[main.c] lock_file(1)" );
  44.  exit ( EXIT_FAILURE );
  45. }
  46. if ( close ( fd ) < 0 )
  47. {
  48.  perror ( "[main.c] close(0)" );
  49.  exit ( EXIT_FAILURE );
  50. }
  51. exit ( EXIT_SUCCESS );
  52. }


 
lock.c

Code :
  1. //--------------------------------------------------------------------
  2. //--------------------------------------------------------------------
  3. /* Lib Name           : file.c
  4. * Ver                : 1.0
  5. * Description        : Provide basic functions to
  6. *    manipulate files.
  7. */
  8. //--------------------------------------------------------------------
  9. #include <fcntl.h>
  10. #include <stdio.h>
  11. #include <errno.h>
  12. #include "lock.h"
  13. //--------------------------------------------------------------------
  14. /* Function Name      : lock_file
  15. * Object             : Lock an opened file.
  16. * Input Parameters   : [int] fd = File descriptor of the file.
  17. *    [int] cmd = kind of lock to apply.
  18. * Output Parameters  : [int] = - '-1' if error.
  19. *     - '0' if no error.
  20. * Functions called   : fcntl().
  21. */
  22. //-------------------------------------------------------------------
  23. int lock_file ( int fd , int cmd )
  24. {
  25. struct flock lock;
  26. /* Setup an exclusive (writing) lock */
  27. lock.l_whence = SEEK_SET;
  28. lock.l_start = 0;
  29. lock.l_len = 0;
  30. /* Apply the lock */
  31. if ( cmd == LOCK_NOWAIT )
  32. {
  33.  lock.l_type = F_WRLCK;
  34.  return fcntl ( fd , F_SETLK , &lock );
  35. }
  36. else if ( cmd == LOCK_WAIT )
  37. {
  38.  lock.l_type = F_WRLCK;
  39.  return fcntl ( fd , F_SETLKW , &lock );
  40. }
  41. else if ( cmd == LOCK_UNLOCK )
  42. {
  43.  lock.l_type = F_UNLCK;
  44.  return fcntl ( fd , F_SETLK , &lock );
  45. }
  46. else
  47. {
  48.  /* Invalid argument */
  49.  errno = EINVAL;
  50.  return -1;
  51. }
  52. }
  53. //--------------------------------------------------------------------
  54. /* Function Name      : lock_is_set
  55. * Object             : Check if an opened file is locked  
  56. *    by AN OTHER processus.
  57. * Input Parameters   : [int] fd = File descriptor of the file.
  58. * Output Parameters  : [int] = - the pid of the process which locked it.
  59. *     - '0' if unlocked.
  60. *     - '-1' if error;
  61. * Functions called   : fcntl().
  62. */
  63. //-------------------------------------------------------------------
  64. int lock_is_set ( int fd )
  65. {
  66. struct flock lock;
  67. /* Test an exclusive (writing) lock */
  68. lock.l_type = F_WRLCK;
  69. lock.l_whence = SEEK_SET;
  70. lock.l_start = 0;
  71. lock.l_len = 0;
  72. /* Apply the lock and check the result */
  73. if ( fcntl ( fd , F_GETLK , &lock ) < 0 )
  74.  return -1;
  75. else if ( lock.l_type == F_UNLCK )
  76.  return 0;
  77. else
  78.  /* lock.l_pid is now the pid of the process
  79.   * owner of the lock */
  80.  return lock.l_pid;
  81. }

Message cité 1 fois
Message édité par escaflownn le 25-10-2006 à 16:57:14
Reply

Marsh Posté le 25-10-2006 à 21:18:00    

escaflownn a écrit :

Merci pour tes précieux conseils.


J'ai pas dit grand chose de réellement utile. Mais si ça marche, tant mieux.


Message édité par Sve@r le 25-10-2006 à 21:18:25

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed