Line data Source code
1 : #include "burp.h"
2 : #include "alloc.h"
3 : #include "lock.h"
4 : #include "log.h"
5 :
6 3 : struct lock *lock_alloc(void)
7 : {
8 186 : return (struct lock *)calloc_w(1, sizeof(struct lock), __func__);
9 : }
10 :
11 186 : int lock_init(struct lock *lock, const char *path)
12 : {
13 186 : free_w(&lock->path);
14 186 : if(!(lock->path=strdup_w(path, __func__)))
15 : return -1;
16 186 : return 0;
17 : }
18 :
19 183 : struct lock *lock_alloc_and_init(const char *path)
20 : {
21 : struct lock *lock;
22 183 : if(!(lock=lock_alloc()) || lock_init(lock, path))
23 0 : lock_free(&lock);
24 183 : return lock;
25 : }
26 :
27 : static void lock_free_content(struct lock *lock)
28 : {
29 185 : free_w(&lock->path);
30 : }
31 :
32 187 : void lock_free(struct lock **lock)
33 : {
34 187 : if(!lock || !*lock) return;
35 370 : lock_free_content(*lock);
36 185 : free_v((void **)lock);
37 : }
38 :
39 9 : void lock_get_quick(struct lock *lock)
40 : {
41 : #if defined(HAVE_WIN32) || !defined(HAVE_LOCKF)
42 : // Would somebody please tell me how to get a lock on Windows?!
43 : lock->status=GET_LOCK_GOT;
44 : return;
45 : #else
46 9 : if((lock->fd=open(
47 9 : lock->path,
48 : #ifdef O_NOFOLLOW
49 : O_NOFOLLOW|
50 : #endif
51 : O_WRONLY|O_CREAT,
52 : 0666
53 : ))<0)
54 : {
55 0 : logp("Could not open lock file %s: %s\n",
56 0 : lock->path, strerror(errno));
57 0 : goto error;
58 : }
59 9 : if(lockf(lock->fd, F_TLOCK, 0))
60 : {
61 1 : if(errno==EACCES || errno==EAGAIN)
62 : goto notgot;
63 0 : logp("Could not get lock %s: %s\n",
64 : lock->path, strerror(errno));
65 0 : goto error; // Some other error.
66 : }
67 8 : if(lock_write_pid(lock))
68 : goto error;
69 :
70 8 : lock->status=GET_LOCK_GOT;
71 8 : return;
72 : error:
73 0 : lock->status=GET_LOCK_ERROR;
74 0 : return;
75 : notgot:
76 1 : lock->status=GET_LOCK_NOT_GOT;
77 1 : return;
78 : #endif
79 : }
80 :
81 8 : int lock_write_pid(struct lock *lock)
82 : {
83 8 : char text[64]="";
84 8 : if(ftruncate(lock->fd, 0))
85 : {
86 0 : logp("Could not ftruncate lock %s: %s\n",
87 0 : lock->path, strerror(errno));
88 0 : return -1;
89 : }
90 8 : if(lseek(lock->fd, 0, SEEK_SET)<0)
91 : {
92 0 : logp("Could not seek to start of lock %s: %s\n",
93 0 : lock->path, strerror(errno));
94 0 : return -1;
95 : }
96 8 : snprintf(text, sizeof(text), "%d\n", (int)getpid());
97 8 : if(write(lock->fd, text, strlen(text))!=(ssize_t)strlen(text))
98 : {
99 0 : logp("Could not write pid/progname to %s: %s\n",
100 0 : lock->path, strerror(errno));
101 0 : return -1;
102 : }
103 : return 0;
104 : }
105 :
106 : // Return 0 for lock got, 1 for lock not got, -1 for error.
107 3 : void lock_get(struct lock *lock)
108 : {
109 : #if defined(HAVE_WIN32) || !defined(HAVE_LOCKF)
110 : // Would somebody please tell me how to get a lock on Windows?!
111 : lock->status=GET_LOCK_GOT;
112 : return;
113 : #else
114 3 : char *cp=NULL;
115 3 : char *copy=NULL;
116 :
117 : // Try to make sure the lock directory exists.
118 3 : if(!(copy=strdup_w(lock->path, __func__)))
119 : {
120 0 : lock->status=GET_LOCK_ERROR;
121 0 : return;
122 : }
123 3 : if((cp=strrchr(copy, '/')))
124 : {
125 3 : *cp='\0';
126 3 : if(*copy) mkdir(copy, 0777);
127 : }
128 3 : free_w(©);
129 :
130 3 : lock_get_quick(lock);
131 :
132 : // Try to make sure the pid gets onto the disk.
133 3 : if(lock->status==GET_LOCK_GOT) fsync(lock->fd);
134 : return;
135 : #endif
136 : }
137 :
138 5 : int lock_test(const char *path)
139 : {
140 : #if defined(HAVE_WIN32) || !defined(HAVE_LOCKF)
141 : // Would somebody please tell me how to test a lock on Windows?!
142 : return 0;
143 : #else
144 5 : int r=0;
145 : int fdlock;
146 :
147 5 : if((fdlock=open(path, O_WRONLY, 0666))<0)
148 : return 0; // file does not exist - could have got the lock
149 2 : errno=0;
150 2 : if((r=lockf(fdlock, F_TLOCK, 0)) && (errno==EAGAIN || errno==EACCES))
151 : {
152 : // could not have got the lock
153 1 : close(fdlock);
154 1 : return -1;
155 : }
156 1 : close(fdlock);
157 : // could have got the lock
158 1 : return 0;
159 : #endif
160 : }
161 :
162 17 : int lock_release(struct lock *lock)
163 : {
164 17 : int ret=0;
165 17 : if(!lock || lock->status!=GET_LOCK_GOT) return 0;
166 7 : if(lock->path) unlink(lock->path);
167 7 : if(lock->fd>=0)
168 : {
169 7 : if((ret=close(lock->fd)))
170 0 : logp("Could not close %s: %s\n",
171 0 : lock->path, strerror(errno));
172 7 : lock->fd=-1;
173 : }
174 7 : lock->status=GET_LOCK_NOT_GOT;
175 7 : return ret;
176 : }
177 :
178 3 : void lock_add_to_list(struct lock **locklist, struct lock *lock)
179 : {
180 3 : if(*locklist) lock->next=*locklist;
181 3 : *locklist=lock;
182 3 : }
183 :
184 4 : void locks_release_and_free(struct lock **locklist)
185 : {
186 : struct lock *l;
187 : struct lock *head;
188 7 : if(!locklist) return;
189 1 : head=*locklist;
190 5 : while(head)
191 : {
192 3 : l=head;
193 3 : head=head->next;
194 3 : lock_release(l);
195 3 : lock_free(&l);
196 : }
197 1 : *locklist=NULL;
198 : }
|