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