/* gip_lock.c Copyright (c) Kapteyn Laboratorium Groningen 1993 All Rights Reserved. #> gip_lock.dc3 Function: gip_lock Purpose: Uses the GIPSY lockserver (see lckserver.doc) to put a lock on a file. The file does not have to exist. Category: SYSTEM File: gip_lock.c Author: K.G. Begeman Call: int gip_lock( char *path ) gip_lock returns 0 on success, or -1 empty path -2 cannot get current working directory -3 unable to read .glock file -4 cannot create socket -5 cannot obtain hostbyname -6 cannot connect to lskserver -7 cannot obtain acknowledgement from lckserver -8 wrong acknowledgement from lckserver -9 cannot start lckserver -10 sudden death of lckserver -11 bad lskserver -12 file was not locked (gip_unlock) -13 file was already locked (gip_lock) -14 lckserver out of sockets -15 bad client -16 unknown error path name of the file Updates: Jan 5, 1993: KGB Document created Dec 5, 2000: JPT Fixed redundant close bug #< #> gip_unlock.dc3 Function: gip_unlock Purpose: Uses the GIPSY lockserver (see lckserver.doc) to remove a lock from a file. The file does not have to exist. Category: SYSTEM File: gip_lock.c Author: K.G. Begeman Call: int gip_unlock( char *path ) gip_unlock returns 0 on success, or -1 empty path -2 cannot get current working directory -3 unable to read .glock file -4 cannot create socket -5 cannot obtain hostbyname -6 cannot connect to lskserver -7 cannot obtain acknowledgement from lckserver -8 wrong acknowledgement from lckserver -9 cannot start lckserver -10 sudden death of lckserver -11 bad lskserver -12 file was not locked (gip_unlock) -13 file was already locked (gip_lock) -14 lckserver out of sockets -15 bad client -16 unknown error path name of the file Updates: Jan 5, 1993: KGB Document created #< */ #include "errno.h" /* */ #include "limits.h" /* */ #include "signal.h" /* */ #include "stdio.h" /* */ #include "stdlib.h" /* */ #include "string.h" /* */ #include "xscanf.h" /* read devces file */ #define GLOCK_CONNECT 1 /* connection made */ #define GLOCK_LOCK 2 /* give lock */ #define GLOCK_NOLOCK 3 /* no lock on file */ #define GLOCK_UNLOCK 4 /* file unlocked */ #define GLOCK_NOSOCK 5 /* no more sockets */ #define GLOCK_ILLEGAL 6 /* illegal request */ #define GLOCK_DISCONNECT 7 /* disconnect from server */ #define GLOCK_ONLOCK 8 /* already locked */ #define GLOCK_ERROR_NOPATH -1 /* empty path */ #define GLOCK_ERROR_GETCWD -2 /* cannot get cwd */ #define GLOCK_ERROR_FILEREAD -3 /* error reading glock file */ #define GLOCK_ERROR_SOCKET -4 /* error creating socket */ #define GLOCK_ERROR_GETHOSTBYNAME -5 /* error gethostbyname */ #define GLOCK_ERROR_CONNECT -6 /* error connect */ #define GLOCK_ERROR_CONNECT1 -7 /* error obtaining ack */ #define GLOCK_ERROR_CONNECT2 -8 /* error in ack */ #define GLOCK_ERROR_SERVERSTART -9 /* error starting server */ #define GLOCK_ERROR_SERVERDEAD -10 /* error server died */ #define GLOCK_ERROR_SERVERBAD -11 /* error from server */ #define GLOCK_ERROR_NOTLOCKED -12 /* file was not locked */ #define GLOCK_ERROR_WASLOCKED -13 /* file was already locked */ #define GLOCK_ERROR_NOSOCKETS -14 /* lskserver out of sockets */ #define GLOCK_ERROR_CLIENTBAD -15 /* bad client */ #define GLOCK_ERROR_UNKNOWN -16 /* ??? */ #define MAXSOCKS 16 /* max. number of sockets */ #define STRINGLEN 250 /* length of strings */ #include /* timeval definitions */ #include /* define some weird types */ #include /* the socket things */ #if defined(__aix__) #include /* special for aix */ #endif #include /* unix things */ #include /* inet things */ #include /* network */ #if !defined(htons) & !defined(__alpha__) & !defined(__linux__) extern u_short htons( ); #endif #if !defined(ntohs) & !defined(__alpha__) & !defined(__linux__) extern u_short ntohs( ); #endif typedef struct { /* the lock struct */ char directory[FILENAME_MAX]; /* directory */ int locks; /* number of locks */ int sock; /* socket to lckserver */ } lock_struct; static int nlocks = 0; /* number of connections */ static lock_struct *mylock = NULL; /* the memory bank */ /* * swapint( ) swaps int integers */ static void swapint( int *l, int nl ) { int i, j; union { char b[sizeof(int)]; int l; } u1, u2; for ( i = 0; i < nl; i++ ) { u1.l = l[i]; for ( j = 0; j < sizeof( int ); j++ ) { u2.b[j] = u1.b[sizeof( int ) - j - 1]; } l[i] = u2.l; } } /* * put( ) puts ndata bytes on the socket and returns 0 on success, * 1 on error. */ static int put( int socket, void *data, int ndata ) { char *p = (char *) data; /* make char pointer */ int count = 0; /* nul write counter */ int nd = 0; /* number of bytes done */ int nl = ndata; /* number of bytes left */ int nt = 0; /* total number of bytes */ int r = 0; /* return value */ int write( ); /* writes on socket */ while (nl) { /* while still some bytes left */ while ((nd = write( socket, &p[nt], nl )) == -1 && errno == EINTR); if (nd < 0) { r = -1; break; } /* an error */ if (!nd && count++ > 10) { r = -1; break; } nl -= nd; /* decrease */ nt += nd; /* increase */ } return( r ); /* return to caller */ } /* * get( ) gets ndata bytes from the socket. It returns 0 on success, * 1 on error. */ static int get( int socket, void *data, int ndata ) { char *p = (char *) data; /* make char pointer */ int count = 0; /* nul read counter */ int nd = 0; /* number of bytes done */ int nl = ndata; /* number of bytes left to do */ int nt = 0; /* total number of bytes */ int r = 0; /* return value */ int read( ); /* read bytes from socket */ while (nl) { /* until nothing left to do */ while ((nd = read( socket, &p[nt], nl )) == -1 && errno == EINTR); if (nd < 0) { r = -1; break; } /* error */ if (!nd && count++ > 10) { r = -1; break; } nl -= nd; /* decrease */ nt += nd; /* increase */ } return( r ); /* return to caller */ } /* * split( ) decomposes a path name into the directory and the filename. */ static int split( char *path, char *dirc, char *name ) { char *s; /* pointer */ int l1, l2; /* length counters */ l1 = strlen( path ); /* length of path */ if ( l1 == 0 ) return( GLOCK_ERROR_NOPATH ); s = strrchr( path, '/' ); /* find last / */ if ( s == NULL ) { /* no directory, so use current */ #if defined(__bsd__) /* get current working directory */ extern char *getwd( ); if ( getwd( dirc ) == NULL ) { #else extern char *getcwd( ); if ( getcwd( dirc, FILENAME_MAX ) == NULL ) { #endif return( GLOCK_ERROR_GETCWD ); } strcpy( name, path ); /* we've got it */ } else { /* strip direcotry from path */ s++; /* after this, the filename */ l2 = strlen( s ); /* length of filename */ if ( l2 == 0 ) return( GLOCK_ERROR_NOPATH ); strcpy( name, s ); /* save file name */ strncpy( dirc, path, l1 - l2 ); /* now the directory */ dirc[l1-l2] = 0; /* add zero */ } l1 = strlen( dirc ); /* length of directory */ if ( dirc[l1-1] != '/' ) { dirc[l1] = '/'; dirc[l1+1] = 0; } return( 0 ); /* we're done */ } /* * makeconnection( ) reads the .glock file and make the connection with * lckserver. */ static int makeconnection( FILE *file ) { char hostname[STRINGLEN]; /* name of host */ int close( ); /* close */ int connect( ); /* connect */ int inet_addr( ); /* get inet address */ int port; /* port number */ int r; /* return value */ int socket( ); /* socket */ int obuf[2]; /* data from lckserver */ short portnumber; /* port number */ struct hostent *gethostbyname( ); /* gethostbyname */ struct hostent *hp; /* host */ struct sockaddr_in server; /* sock struct */ if ( xscanf( file, "%s %d", hostname, &port ) != 2 ) { fclose( file ); return( GLOCK_ERROR_FILEREAD ); } fclose( file ); /* close .glock file */ portnumber = port; /* the port */ r = socket( AF_INET, SOCK_STREAM, 0 ); /* create socket */ if ( r == -1 ) return( GLOCK_ERROR_SOCKET ); /* error */ hp = gethostbyname( hostname ); /* get host by name */ if ( hp == NULL ) { /* error */ server.sin_addr.s_addr = inet_addr( hostname ); if (server.sin_addr.s_addr == -1) { close( r ); return( GLOCK_ERROR_GETHOSTBYNAME ); } } else { server.sin_addr.s_addr = INADDR_ANY; /* any address */ memmove( (void *) &server.sin_addr, (void *) hp->h_addr, hp->h_length ); } server.sin_family = AF_INET; /* inet */ server.sin_port = htons( portnumber ); /* the port */ if ( connect( r, (void *) &server, sizeof( server ) ) == -1 ) { close( r ); return( GLOCK_ERROR_CONNECT ); } else { /* connection okay */ if ( get( r, obuf, sizeof( obuf ) ) ) { close( r ); return( GLOCK_ERROR_CONNECT1 ); /* error */ } if ( obuf[0] != 1 ) swapint( obuf, 2 ); /* swap bytes */ if ( obuf[0] != 1 ) { /* error */ close( r ); return( GLOCK_ERROR_CONNECT2 ); } else if ( obuf[1] != GLOCK_CONNECT ) { /* error */ close( r ); if ( obuf[1] == GLOCK_NOSOCK ) { return( GLOCK_ERROR_NOSOCKETS ); } else { return( GLOCK_ERROR_SERVERBAD ); } } } return( r ); /* we're done */ } /* * serveropen( ) starts locker. */ static FILE *serveropen( char *dirc, int clear ) { FILE *r; /* points to .glock */ char filename[FILENAME_MAX]; /* name of .glock */ sprintf( filename, "%s.glock", dirc ); /* make filename */ if ( clear ) remove( filename ); /* remove it */ r = fopen( filename, "r" ); /* open it */ if ( r == NULL ) { /* error */ char cmd[STRINGLEN]; /* command */ #ifndef TESTBED sprintf( cmd, "$gip_exe/lckserver %s", dirc ); #else sprintf( cmd, "./lckserver %s", dirc ); #endif if ( system( cmd ) ) return( NULL ); /* error */ sleep(2); /* allow lckserver to start */ r = fopen( filename, "r" ); } return( r ); /* we're done */ } /* * getsock( ) make the connection with the locker. */ static int getsock( char *dirc ) { FILE *file; /* points to .glock */ int r = 0; /* return value */ file = serveropen( dirc, 0 ); /* open server */ if ( file == NULL ) return( GLOCK_ERROR_SERVERSTART ); r = makeconnection( file ); /* make connection */ if ( r < 0 ) { /* error */ file = serveropen( dirc, 1 ); if ( file == NULL ) return( GLOCK_ERROR_SERVERSTART ); r = makeconnection( file ); } return( r ); /* we're done */ } /* * contact( ) connects to the lock server. */ static int contact( char *dirc ) { int s = 0; int sock; while ( s < nlocks && strcmp( mylock[s].directory, dirc ) ) s++; if ( s == nlocks ) { /* not in list */ mylock = realloc( mylock, sizeof( lock_struct ) * ++nlocks ); strcpy( mylock[s].directory, dirc ); mylock[s].locks = 0; } else if ( mylock[s].locks ) { /* still open */ return( s ); } if ( ( sock = getsock( dirc ) ) < 0 ) { /* get socket */ return( sock ); /* error */ } else { /* done */ mylock[s].sock = sock; return( s ); } } /* * dolock( ) does the (un)locking. */ static int dolock( char *path, int lockopt ) { char dirc[FILENAME_MAX]; /* the directory */ char name[FILENAME_MAX]; /* the name */ int close( ); int s; int r; int ibuf[3]; /* to server */ int obuf[2]; /* from server */ r = split( path, dirc, name ); /* split */ if ( r ) return( r ); /* error */ s = contact( dirc ); /* contact lckserver */ if ( s < 0 ) return( s ); /* error */ ibuf[0] = 1; ibuf[1] = lockopt; ibuf[2] = strlen( name ); if ( put( mylock[s].sock, ibuf, sizeof( ibuf ) ) ) { close( mylock[s].sock ); /* error */ mylock[s].locks = 0; return( GLOCK_ERROR_SERVERDEAD ); } if ( put( mylock[s].sock, name, strlen( name ) ) ) { close( mylock[s].sock ); /* error */ mylock[s].locks = 0; return( GLOCK_ERROR_SERVERDEAD ); } if ( get( mylock[s].sock, obuf, sizeof( obuf ) ) ) { close( mylock[s].sock ); /* error */ mylock[s].locks = 0; return( GLOCK_ERROR_SERVERDEAD ); } if ( obuf[0] != 1 ) swapint( obuf, 2 ); /* swap bytes */ if ( obuf[0] != 1 ) { close( mylock[s].sock ); /* error */ mylock[s].locks = 0; return( GLOCK_ERROR_SERVERBAD ); } switch( obuf[1] ) { /* what happened ? */ case GLOCK_LOCK: { /* we got a lock */ mylock[s].locks += 1; break; } case GLOCK_NOLOCK: { /* there was no lock */ r = GLOCK_ERROR_NOTLOCKED; break; } case GLOCK_ONLOCK: { /* was already locked */ r = GLOCK_ERROR_WASLOCKED; break; } case GLOCK_UNLOCK: { /* removed lock */ mylock[s].locks -= 1; if ( !mylock[s].locks ) { /* disconnect from server */ ibuf[0] = 1; ibuf[1] = GLOCK_DISCONNECT; ibuf[2] = 0; put( mylock[s].sock, ibuf, sizeof( ibuf ) ); close( mylock[s].sock ); } break; } case GLOCK_ILLEGAL: { /* we did something wrong */ r = GLOCK_ERROR_CLIENTBAD; break; } default: { /* ??? */ r = GLOCK_ERROR_UNKNOWN; break; } } return( r ); } /* * gip_lock( ) puts a lock on a file. */ int gip_lock( char *path ) { return( dolock( path, GLOCK_LOCK ) ); } /* * gip_unlock( ) removes a lock. */ int gip_unlock( char *path ) { return( dolock( path, GLOCK_UNLOCK ) ); } #ifdef TESTBED int main( int argc, char *argv[] ) { int iarg; int sleep( ); for ( iarg = 1; iarg < argc; iarg += 2 ) { printf( "gip_lock = %4d\n", gip_lock( argv[iarg] ) ); sleep( atoi( argv[iarg+1] ) ); } for ( iarg = 1; iarg < argc; iarg += 2 ) { printf( "gip_unlock = %4d\n", gip_unlock( argv[iarg] ) ); sleep( atoi( argv[iarg+1] ) ); } return( 0 ); } #endif