1 /*
2 * IceBreaker
3 * Copyright (c) 2002 Matthew Miller <mattdm@mattdm.org> and
4 *  Enrico Tassi <gareuselesinge@infinito.it>
5 *
6 * <http://www.mattdm.org/icebreaker/>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc., 59
20 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23 
24 
25 #ifndef WIN32
26   #include <fcntl.h>
27   #include <unistd.h>
28   #include <string.h>
29 #endif
30 
31 #include "lock.h"
32 
33 // the return value of lock/unlock system calls
34 static int sysret;
35 
36 // the number of times to retry before returning from lock()
37 #define RETRY_N 3
38 
39 // the number of seconds between two lock syscalls (in seconds)
40 #define INTERVAL 1
41 
42 //***************** OH MY  *******************************************
43 // And now for a bunch of crazy cross-platform macros devised
44 // by Enrico. :)
45 
46 
47 //***************** LOCK_DEBUG MACRO *********************************
48 //#include "stdio.h"
49 //#define LOCK_DEBUG(a...) fprintf(stderr,a)
50 #define LOCK_DEBUG(a...)
51 
52 //***************** SYSCALL WRAPPING *********************************
53 #ifdef WIN32
54 
55 # define DELAY          	(INTERVAL * 1000)
56 # define LOCK_SYSCALL(a)   	{sysret=LockFile(a,0,0,1,0);}
57 # define UNLOCK_SYSCALL(a) 	{sysret=UnlockFile(a,0,0,1,0);}
58 # define OPEN_SYSCALL(a)	CreateFile(a,GENERIC_READ,1,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,NULL)
59 # define CLOSE_SYSCALL(a)	CloseHandle(a)
60 # define SLEEP_SYSCALL()	Sleep(DELAY)
61 # define BAD_VALUE 		0
62 # define IS_OK(a)		(a != BAD_VALUE)
63 
64 #else
65 
66 static struct flock lockstr;	// used by fcntl
67 # define DELAY          	INTERVAL
68 # define LOCK_SYSCALL(a)   	{memset(&lockstr,0,sizeof(lockstr));lockstr.l_type = F_WRLCK;sysret = fcntl(a, F_SETLK , &lockstr);}
69 # define UNLOCK_SYSCALL(a)      {memset(&lockstr,0,sizeof(lockstr));lockstr.l_type = F_UNLCK;sysret = fcntl(a, F_SETLK , &lockstr);}
70 # define OPEN_SYSCALL(a)	open(a,O_RDWR)
71 # define CLOSE_SYSCALL(a)	close(a)
72 # define SLEEP_SYSCALL()	sleep(DELAY)
73 # define BAD_VALUE 		-1
74 # define IS_OK(a)		(a != BAD_VALUE)
75 
76 #endif
77 
78 //************************ REAL FUNCTIONS ****************************
79 
80 /*  return values:
81  *     0  = success
82  *     -1 = lock failed
83  */
lock(FILE_DESC f)84 int lock(FILE_DESC f)
85 {
86 	int i;
87 	sysret = BAD_VALUE;
88 
89 	for( i = 0 ; i < RETRY_N  && !IS_OK(sysret) ; i++ )
90 	{
91 		LOCK_SYSCALL(f);
92 
93 		if(!IS_OK(sysret) && i < RETRY_N -1)
94 		{
95 			SLEEP_SYSCALL();
96 		}
97 	}
98 
99 	if(IS_OK(sysret))
100 	{
101 		LOCK_DEBUG("lock obtained\n");
102 		return 0;
103 	}
104 	else
105 	{
106 		LOCK_DEBUG("lock denied\n");
107 		return -1;
108 	}
109 }
110 
111 /*  return values:
112  *     0  = success
113  *     -1 = unlock failed
114  */
unlock(FILE_DESC f)115 int unlock(FILE_DESC f)
116 {
117 
118 	UNLOCK_SYSCALL(f);
119 
120 	if(!IS_OK(sysret))
121 	{
122 		LOCK_DEBUG("unlock failed\n");
123 		// FIX: do something to warn about this, because it shouldn't
124 		// happen and will definitely cause problems if it does.
125 		return -1;
126 	}
127 	else
128 	{
129 		LOCK_DEBUG("unlocked\n");
130 		return 0;
131 	}
132 
133 }
134 
135 /*  return values:
136  *     ?                 = success
137  *     INVALID_FILE_DESC = failed
138  */
openlockfile(char * fname)139 FILE_DESC openlockfile(char* fname)
140 {
141 	return OPEN_SYSCALL(fname);
142 }
143 
closelockfile(FILE_DESC f)144 void closelockfile(FILE_DESC f)
145 {
146 	CLOSE_SYSCALL(f);
147 }
148 
149