/************************************************************************ * Whatever is needed for (un)locking files in various ways * * * * Copyright (c) 1990-1997, S.R. van den Berg, The Netherlands * * #include "../README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: locking.c,v 1.7 1998/05/13 16:57:40 srb Exp $"; #endif #include "config.h" #include #include #include #include #include #include #include #include "cucipop.h" #include "locking.h" #ifndef USEfcntl_lock #ifndef USElockf #ifndef USEflock #ifndef USEdot_lock #error No locking mechanism enabled #endif #define fdlock(fd) 0 #define fdunlock() 0 #endif #endif #endif #ifndef fdlock static int fdlock(int fd); static int fdunlock(void); #endif #ifndef tell #define tell(fd) lseek(fd,0L,SEEK_CUR) #endif static char*lastlocked; static const char lockext[]=".lock"; void unlockmbox(void) { fdunlock(); #ifdef USEdot_lock blocksignals(); if(lastlocked) unlink(lastlocked),free(lastlocked),lastlocked=0; #endif } int lockmbox(int fd,const char*mbox) { char*ll; if(fdlock(fd)) return 0; #ifdef USEdot_lock if(ll=malloc(strlen(mbox)+STRLEN(lockext)+1)) { strcpy(ll,mbox);strcat(ll,lockext); for(;;) { blocksignals(); switch(xcreat(ll,0644)) { case 0:lastlocked=ll;setsignals(); return 1; default:setsignals(); thatsall: free(ll); return 0; case -1:setsignals();sleep(LOCKSLEEP); if(spoofcheck>=0) { int fdsockin=fileno(sockin),res;char c; fcntl(fdsockin,F_SETFL,(long)O_NONBLOCK); res=read(fdsockin,&c,1);fcntl(fdsockin,F_SETFL,0L); switch(res) { case 0: goto thatsall; case 1:spoofcheck=-1;ungetc(c,sockin); } } } } } return 0; #else return 1; #endif } /* if you've ever wondered what conditional compilation was good for */ #ifndef fdlock /* watch closely :-) */ #ifdef USEflock #ifndef SYS_FILE_H_MISSING #include #endif #define REITflock 1 #else #define REITflock 0 #endif /* USEflock */ static int oldfdlock= -1; /* the fd we locked last */ #ifndef NOfcntl_lock static struct flock flck; /* why can't it be a local variable? */ #define REITfcntl 1 #else #define REITfcntl 0 #endif /* NOfcntl_lock */ #ifdef USElockf static off_t oldlockoffset; #define REITlockf 1 #else #define REITlockf 0 #endif /* USElockf */ static int fdlock(int fd) { int ret; #if REITfcntl+REITflock+REITlockf>1 for(;;syslog(LOG_DEBUG,"reiterating kernel-lock"),sleep(LOCKSLEEP)) #endif { #ifdef USElockf oldlockoffset=0; #endif #ifndef NOfcntl_lock flck.l_type=F_WRLCK;flck.l_whence=SEEK_SET;flck.l_len=0; #ifdef USElockf flck.l_start=oldlockoffset; #else flck.l_start=tell(fd); #endif #endif #ifndef NOfcntl_lock ret=fcntl(fd,F_SETLKW,&flck); #ifdef USElockf if((ret|=lockf(fd,F_TLOCK,(off_t)0))&&(errno==EAGAIN||errno==EACCES|| errno==EWOULDBLOCK)) ufcntl: { flck.l_type=F_UNLCK;fcntl(fd,F_SETLK,&flck); continue; } #ifdef USEflock if((ret|=flock(fd,LOCK_EX|LOCK_NB))&&(errno==EAGAIN||errno==EACCES|| errno==EWOULDBLOCK)) { lockf(fd,F_ULOCK,(off_t)0); goto ufcntl; } #endif /* USEflock */ #else /* USElockf */ #ifdef USEflock if((ret|=flock(fd,LOCK_EX|LOCK_NB))&&(errno==EAGAIN||errno==EACCES|| errno==EWOULDBLOCK)) { flck.l_type=F_UNLCK;fcntl(fd,F_SETLK,&flck); continue; } #endif /* USEflock */ #endif /* USElockf */ #else /* NOfcntl_lock */ #ifdef USElockf ret=lockf(fd,F_LOCK,(off_t)0); #ifdef USEflock if((ret|=flock(fd,LOCK_EX|LOCK_NB))&&(errno==EAGAIN||errno==EACCES|| errno==EWOULDBLOCK)) { lockf(fd,F_ULOCK,(off_t)0); continue; } #endif /* USEflock */ #else /* USElockf */ #ifdef USEflock ret=flock(fd,LOCK_EX); #endif /* USEflock */ #endif /* USElockf */ #endif /* NOfcntl_lock */ oldfdlock=fd; return ret; } } static int fdunlock(void) { int i; if(oldfdlock<0) return -1; i=0; #ifdef USEflock i|=flock(oldfdlock,LOCK_UN); #endif #ifdef USElockf ;{ off_t curp=tell(oldfdlock); lseek(oldfdlock,oldlockoffset,SEEK_SET); i|=lockf(oldfdlock,F_ULOCK,(off_t)0);lseek(oldfdlock,curp,SEEK_SET); } #endif #ifndef NOfcntl_lock flck.l_type=F_UNLCK;i|=fcntl(oldfdlock,F_SETLK,&flck); #endif oldfdlock= -1; return i; } #endif /* fdlock */