Sujet : [C Linux] Pose de verrou via fcntl()

Bah ouais, une colle pas évidente, pour s'assurer que y'a pas que des gifs d'anal fucking mais aussi du brainstorming sur l'asile.

Alors voila le topo 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.

Le code n'est pas coloré par le forum, donc payes tes yeux à l'arrivée.


main.c

#include <stdio.h>
#include <stdlib.h>
#include <socket.h>
#include <unistd.h>

const char test[3]="ab";

int main ( int argc , char** argv )
{
    int fd;

    chdir ( "/tmp" );

    if ( ( fd = open_socket ( "socket.tmp" ) ) < 0 )
    {
        printf ( "Cannot create socket file\n" );
        exit ( -1 );
    }

    printf ( "Press <RETURN> to set lock\n" );
    getchar ();

    if ( lock_socket ( fd ) < 0 )
    {
        printf ( "Cannot lock socket file\n" );
        exit ( -1 );
    }

    printf ( "Lock Status = %d\n" , is_locked_socket ( fd ) );

    lseek ( fd , 0 , SEEK_END );
    write ( fd , &test[0] , 2 );

    printf ( "Press <RETURN> to remove lock\n" );
    getchar ();

    if ( unlock_socket ( fd ) < 0 )
        exit ( -1 );

    if ( close_socket ( fd ) < 0 )
        exit ( -1 );
    
    exit ( EXIT_SUCCESS );

socket.c

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "socket.h"
#include <stdio.h>

//--------------------------------------------------------------------
/* Function Name      : open_socket
 * Object             : Opens an existing socket or creates it !
 * Input Parameters   : [char*] path = Name of the socket file.
 * Output Parameters  : [int] = File descriptor of the socket file.
 *                 '-1' if error.
 * Functions called   : open(),lseek().
 */
//--------------------------------------------------------------------
int open_socket ( char* path )
{
    int err, fd;
    
    /* OPEN the file */
    fd = open ( path , O_RDWR | O_CREAT,
            S_IRUSR | S_IWUSR );
    if ( fd < 0 ) 
        return SOCKET_ERROR; 

    /* JUMP at the beginning of the file */
    err = lseek ( fd , 0 , SEEK_SET );
    if ( err < 0 )
        return SOCKET_ERROR;
    
    return fd;
}

//--------------------------------------------------------------------
/* Function Name      : close_socket
 * Object             : Close an existing socket.
 * Input Parameters   : [int] fd = File descriptor of the socket file.
 * Output Parameters  : [int] = exit status.
 *                 '-1' if error.
 *                 '0' if no error.
 * Functions called   : close().
 */
int close_socket ( int fd )
{
    return close ( fd );
}

//--------------------------------------------------------------------
/* Function Name      : unlock_socket
 * Object             : Unlock an existing socket.
 * Input Parameters   : [int] fd = File descriptor of the socket file.
 * Output Parameters  : [int] = exit status.
 *                 '-1' if error.
 *                 '0' if no error.
 * Functions called   : fcntl().
 */
//-------------------------------------------------------------------
int unlock_socket ( int fd ) 
{
    static struct flock lock;
    
    lock.l_type = F_UNLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;

    return fcntl ( fd , F_SETLKW , &lock );
}

//--------------------------------------------------------------------
/* Function Name      : lock_socket
 * Object             : Lock an existing socket.
 * Input Parameters   : [int] fd = File descriptor of the socket file.
 * Output Parameters  : [int] = exit status.
 *                 '-1' if error.
 *                 '0' if no error.
 * Functions called   : fcntl().
 */
//-------------------------------------------------------------------
int lock_socket ( int fd ) 
{
    static struct flock lock;
    
    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;

    return fcntl ( fd , F_SETLKW , &lock );
}

//--------------------------------------------------------------------
/* Function Name      : is_locked_socket
 * Object             : Check if an existing socket is locked.
 * Input Parameters   : [int] fd = File descriptor of the socket file.
 * Output Parameters  : [int] = exit status.
 *                 the pid of the process if locked.
 *                 '0' if unlocked.
 *                 '-1' if error;
 * Functions called   : fcntl().
 */
//-------------------------------------------------------------------
int is_locked_socket ( int fd ) 
{
    static struct flock lock;

    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;

    if ( fcntl ( fd , F_GETLK , &lock ) == -1 )
        return -1;

    if ( lock.l_type == F_UNLCK )
        return 0;
    else
        return lock.l_pid;
}

Aller les mecs.

su-per

2

Re : [C Linux] Pose de verrou via fcntl()

Facile, achète un mac.

Envoyé depuis mon IPhone.

3

Re : [C Linux] Pose de verrou via fcntl()

Ca mérite une place en une, à n'en pas douter.

4

Re : [C Linux] Pose de verrou via fcntl()

Putain, grave.

5 Dernière modification par mr_zlu (24-10-2006 21:44:51)

Re : [C Linux] Pose de verrou via fcntl()

Oui, mais pourquoi nous on a pas droit aussi au lettre d'amour de mecs largués ou blog de gens qui ecoutent du black metal avec l'envie de se suicider, ou bien seskemachien tout court, comme sur nofrag?

Envoyé depuis mon IPhone.

Re : [C Linux] Pose de verrou via fcntl()

Tu peux te contenter de ça pour l'instant non ?

7

Re : [C Linux] Pose de verrou via fcntl()

Hop, c'est résolu, je vous balance pas la soluce parce que vous n'en avez rien à secouer!

Sinon merci pour la home.
Autant le virer de là maintenant, ça fait tâche à côté du bel article de Troy.

su-per

8

Re : [C Linux] Pose de verrou via fcntl()

Je pète.

C'est mon idée la glue dans les lance flammes.

9

Re : [C Linux] Pose de verrou via fcntl()

C'est le genre d'article qui me ferait fuir si j'etais nouveau et que je debarquais ici (attention je ne suis pas en train de troller sur Linux ni sur Plume), mais en home c'est limite, je prefererai un article sur les bites en forme de pelle.

PUTEDEPUTEDEPUTE

10

Re : [C Linux] Pose de verrou via fcntl()

pololefou a écrit:

Balance la soluce, si y'a un con sur le net qui cherche un truc dans le genre, il te considèrera comme sa lumière dans les ténèbres de l'informatique.

Et me prendra pour un cas social flatulant sur un topic linux. Classe.

C'est mon idée la glue dans les lance flammes.

Re : [C Linux] Pose de verrou via fcntl()

Plume a écrit:

Hop, c'est résolu, je vous balance pas la soluce parce que vous n'en avez rien à secouer!

Sinon merci pour la home.
Autant le virer de là maintenant, ça fait tâche à côté du bel article de Troy.

Si si la soluce ! Moi elle m'interesse aussi...

12

Re : [C Linux] Pose de verrou via fcntl()

C'est vrai que nofrag n'a jamais été aussi lol, bon ok, jamais aussi pathétique non plus.
Mais c'est quand même roflifiant de pourrir le blog d'un type qui pense pouvoir trouver des réponses existentielles dans ce méga tas de merde. Un peu comme dans les pays pauvres qui passent à la télé, où les enfants crèvent à 7 ans dans les énormes décharges à force de chercher des piles à la main pour les vendre (ou pour les manger).

13

Re : [C Linux] Pose de verrou via fcntl()

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 lock_is_set() 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 dont il est le propriétaire. C'est pour cette raison qu'elle renvoyait 0 dans tous les cas.

main.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "lock.h"
 
int main ( int argc , char** argv )
{
    int fd;
    char tab[4] = "ab\n";

    if ( chdir ( "/tmp" ) < 0 )
    {
        perror ( "[main.c] chdir(0)" );
        exit ( EXIT_FAILURE );
    }

    fd = open ( "fic_test.tmp" , O_RDWR | O_CREAT , S_IRWXU );
    if ( fd < 0 )
    {
        perror ( "[main.c] open(0)" );
        exit ( EXIT_FAILURE );
    }

    if ( lock_file ( fd , LOCK_NOWAIT ) < 0 )
    {
        perror ( "[main.c] lock_file(0)" );
        exit ( EXIT_FAILURE );
    }
    
    if ( lseek ( fd , 0 , SEEK_END ) < 0 )
    {
        perror ( "[main.c] lseek(0)" );
        exit ( EXIT_FAILURE );
    }

    printf ( "Press <RETURN> to continue\n" );
    getchar ( );

    if ( write ( fd , &tab[0] , 3 ) < 0 )
    {
        perror ( "[main.c] write(0)" );
        exit ( EXIT_FAILURE );
    }

    if ( lock_file ( fd , LOCK_UNLOCK ) < 0 )
    {
        perror ( "[main.c] lock_file(1)" );
        exit ( EXIT_FAILURE );
    }

    if ( close ( fd ) < 0 )
    {
        perror ( "[main.c] close(0)" );
        exit ( EXIT_FAILURE );
    }
    
    exit ( EXIT_SUCCESS );
}

lock.c

//--------------------------------------------------------------------
//--------------------------------------------------------------------
/* Lib Name           : file.c
 * Ver                : 1.0
 * Description        : Provide basic functions to
 *             manipulate files.
 */
//--------------------------------------------------------------------

#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

#include "lock.h"

//--------------------------------------------------------------------
/* Function Name      : lock_file
 * Object             : Lock an opened file.
 * Input Parameters   : [int] fd = File descriptor of the file.
 *             [int] cmd = kind of lock to apply.
 * Output Parameters  : [int] = - '-1' if error.
 *                 - '0' if no error.
 * Functions called   : fcntl().
 */
//-------------------------------------------------------------------
int lock_file ( int fd , int cmd ) 
{
    struct flock lock;

    /* Setup an exclusive (writing) lock */
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;

    /* Apply the lock */

    if ( cmd == LOCK_NOWAIT )
    {
        lock.l_type = F_WRLCK;
        return fcntl ( fd , F_SETLK , &lock );
    }
    else if ( cmd == LOCK_WAIT )
    {
        lock.l_type = F_WRLCK;
        return fcntl ( fd , F_SETLKW , &lock );
    }
    else if ( cmd == LOCK_UNLOCK )
    {
        lock.l_type = F_UNLCK;
        return fcntl ( fd , F_SETLK , &lock );
    }
    else
    {
        /* Invalid argument */
        errno = EINVAL;
        return -1;
    }
}

//--------------------------------------------------------------------
/* Function Name      : lock_is_set
 * Object             : Check if an opened file is locked 
 *             by AN OTHER processus.
 * Input Parameters   : [int] fd = File descriptor of the file.
 * Output Parameters  : [int] = - the pid of the process which locked it.
 *                 - '0' if unlocked.
 *                 - '-1' if error;
 * Functions called   : fcntl().
 */
//-------------------------------------------------------------------
int lock_is_set ( int fd ) 
{
    struct flock lock;

    /* Test an exclusive (writing) lock */
    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;

    /* Apply the lock and check the result */
    if ( fcntl ( fd , F_GETLK , &lock ) < 0 )
        return -1;

    else if ( lock.l_type == F_UNLCK )
        return 0;
    else
        /* lock.l_pid is now the pid of the process
         * owner of the lock */
        return lock.l_pid;
}

Massez moi les pieds.

su-per

14

Re : [C Linux] Pose de verrou via fcntl()

Il y avait moyen de faire plus simple... Je posterai ça demain

Inséminateur de femmes ménopauséent