1 #define _XOPEN_SOURCE 500
2 #include <sys/types.h>
3 #include <signal.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <assert.h>
10 #include <errno.h>
11
12 struct lock_file {
13 char * file;
14 struct lock_file * next;
15 };
16
17 static struct lock_file * lf_list = NULL;
18
free_lockfile(struct lock_file * pre,struct lock_file * cur)19 static void free_lockfile(struct lock_file * pre, struct lock_file * cur)
20 {
21 if (cur == lf_list)
22 {
23 lf_list = cur->next;
24 }
25 else
26 {
27 assert(pre != cur);
28 pre->next = cur->next;
29 }
30 free(cur->file); free(cur);
31 return;
32 }
33
free_this_lockfile(char * file)34 static void free_this_lockfile(char * file)
35 {
36 struct lock_file * pre = lf_list;
37 struct lock_file * cur = lf_list;
38
39 while (cur)
40 {
41 if (0 == strcmp(cur->file, file))
42 {
43 free_lockfile(pre, cur);
44 return;
45 }
46 pre = cur;
47 cur = cur->next;
48 }
49 return;
50 }
51
add_this_lockfile(char * file)52 static void add_this_lockfile(char * file)
53 {
54 struct lock_file * cur = malloc(sizeof(struct lock_file));
55
56 if (cur)
57 {
58 size_t len = 1 + strlen(file);
59 cur->file = malloc(len);
60 strcpy(cur->file, file);
61 /* cur->file = strdup(file); *//* osx doesn't have it */
62 cur->next = lf_list;
63 lf_list = cur;
64 }
65 return;
66 }
67
remove_all_locks()68 void remove_all_locks()
69 {
70 struct lock_file * cur = lf_list;
71
72 while (cur)
73 {
74 unlink(cur->file);
75 cur = cur->next;
76 }
77 return;
78 }
79
80
write_pid(int fd)81 static int write_pid(int fd)
82 {
83 pid_t pid = getpid();
84 FILE * fp;
85
86 fp = fdopen(fd, "w");
87 if (!fp)
88 {
89 perror("write_pid: fdopen");
90 return -1;
91 }
92
93 if (fprintf(fp, "%d", (int) pid) < 0)
94 {
95 perror("write_pid: fprintf");
96 return -1;
97 }
98
99 if (0 != fclose(fp))
100 {
101 perror("write_pid: fclose");
102 return -1;
103 }
104 return 0;
105 }
106
pid_valid(int pid)107 static int pid_valid(int pid)
108 {
109 return kill(pid, 0);
110 }
111
test_lock(char * lockfile)112 static int test_lock(char * lockfile)
113 {
114 int fpid;
115 int pid = (int) getpid();
116 FILE * fp = fopen(lockfile, "r");
117
118 if (!fp)
119 {
120 perror("test_lock: fopen");
121 return -1;
122 }
123 if (1 != fscanf(fp, "%d", &fpid))
124 {
125 perror("test_lock: fscanf");
126 fclose(fp);
127 return -1;
128 }
129 if (pid != fpid)
130 {
131 fclose(fp);
132 return pid_valid(fpid);
133 }
134
135 fclose(fp);
136 return 0;
137 }
138
try_lock(char * template,char * lockfile)139 static int try_lock(char * template, char * lockfile)
140 {
141 int ret = 0;
142 int ttt = 5;
143
144 do {
145 ret = link(template, lockfile);
146 if (ret == -1)
147 {
148 if (errno == EEXIST)
149 {
150 sleep(ttt);
151 ttt+= 5;
152 }
153 else
154 {
155 perror("try_lock: link");
156 return -1;
157 }
158 }
159 } while (ret < 0 && ttt < 65);
160
161 return ret;
162 }
163
create_lockfile(char * lockfile)164 static int create_lockfile(char * lockfile)
165 {
166 int fd;
167 int ret;
168 char * template = malloc(strlen(lockfile) + 7);
169
170 assert(template != NULL);
171
172 strcpy(template, lockfile);
173 strcat(template, "XXXXXX");
174
175 fd = mkstemp(template);
176 if (fd == -1)
177 {
178 free(template);
179 perror("create_lockfile: mkstemp");
180 return -1;
181 }
182
183 if (write_pid(fd) == -1)
184 {
185 unlink(template);
186 free(template);
187 return -1;
188 }
189
190 ret = try_lock(template, lockfile);
191 if (ret < 0)
192 {
193 unlink(template);
194 free(template);
195 return -1;
196 }
197
198 unlink(template);
199 free(template);
200 return 0;
201 }
202
acquire_lock(char * file)203 int acquire_lock(char * file)
204 {
205 char * lockfile = malloc(strlen(file) + 6);
206
207 assert(lockfile != NULL);
208
209 strcpy(lockfile, file);
210 strcat(lockfile, ".lock");
211
212 add_this_lockfile(lockfile);
213 if (create_lockfile(lockfile) < 0)
214 {
215 free_this_lockfile(lockfile);
216 free(lockfile);
217 return -1;
218 }
219
220
221 free(lockfile);
222 return 0;
223 }
224
valid_lock(char * file)225 int valid_lock(char * file)
226 {
227 struct stat buf;
228 int ret;
229 char * lockfile = malloc(strlen(file) + 6);
230
231 assert(lockfile != NULL);
232
233 strcpy(lockfile, file);
234 strcat(lockfile, ".lock");
235
236 ret = stat(lockfile, &buf);
237 if (ret < 0)
238 {
239 free(lockfile);
240 return -1;
241 }
242
243 ret = test_lock(lockfile);
244 return ret;
245 }
246
remove_lock(char * file)247 int remove_lock(char * file)
248 {
249 int ret;
250 char * lockfile = malloc(strlen(file) + 6);
251
252 assert(lockfile != NULL);
253
254 strcpy(lockfile, file);
255 strcat(lockfile, ".lock");
256
257 ret = unlink(lockfile);
258
259 if (ret < 0 && errno != ENOENT)
260 {
261 perror("remove_lock: unlink");
262 ret = -1;
263 }
264 else
265 {
266 free_this_lockfile(lockfile);
267 ret = 0;
268 }
269
270 free(lockfile);
271 return ret;
272 }
273
274
275