Line data Source code
1 : #include "burp.h"
2 : #include "alloc.h"
3 : #include "lock.h"
4 : #include "log.h"
5 :
6 17 : struct lock *lock_alloc(void)
7 : {
8 462 : return (struct lock *)calloc_w(1, sizeof(struct lock), __func__);
9 : }
10 :
11 463 : int lock_init(struct lock *lock, const char *path)
12 : {
13 463 : free_w(&lock->path);
14 463 : if(!(lock->path=strdup_w(path, __func__)))
15 : return -1;
16 463 : return 0;
17 : }
18 :
19 445 : struct lock *lock_alloc_and_init(const char *path)
20 : {
21 : struct lock *lock;
22 445 : if(!(lock=lock_alloc()) || lock_init(lock, path))
23 0 : lock_free(&lock);
24 445 : return lock;
25 : }
26 :
27 : static void lock_free_content(struct lock *lock)
28 : {
29 461 : free_w(&lock->path);
30 : }
31 :
32 470 : void lock_free(struct lock **lock)
33 : {
34 470 : if(!lock || !*lock) return;
35 922 : lock_free_content(*lock);
36 461 : free_v((void **)lock);
37 : }
38 :
39 102 : 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 102 : if((lock->fd=open(
47 102 : 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 102 : if(lockf(lock->fd, F_TLOCK, 0))
60 : {
61 2 : 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 100 : if(lock_write_pid_and_prog(lock))
68 : goto error;
69 :
70 100 : lock->status=GET_LOCK_GOT;
71 100 : return;
72 : error:
73 0 : lock->status=GET_LOCK_ERROR;
74 0 : return;
75 : notgot:
76 2 : lock->status=GET_LOCK_NOT_GOT;
77 2 : return;
78 : #endif
79 : }
80 :
81 100 : int lock_write_pid_and_prog(struct lock *lock)
82 : {
83 100 : char text[64]="";
84 100 : 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 100 : 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 100 : snprintf(text, sizeof(text), "%d\n%s\n", (int)getpid(), progname());
97 100 : 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 81 : 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 81 : char *cp=NULL;
115 81 : char *copy=NULL;
116 :
117 : // Try to make sure the lock directory exists.
118 81 : if(!(copy=strdup_w(lock->path, __func__)))
119 : {
120 0 : lock->status=GET_LOCK_ERROR;
121 0 : return;
122 : }
123 81 : if((cp=strrchr(copy, '/')))
124 : {
125 81 : *cp='\0';
126 81 : if(*copy) mkdir(copy, 0777);
127 : }
128 81 : free_w(©);
129 :
130 81 : lock_get_quick(lock);
131 :
132 : // Try to make sure the pid gets onto the disk.
133 81 : if(lock->status==GET_LOCK_GOT) fsync(lock->fd);
134 : return;
135 : #endif
136 : }
137 :
138 11 : 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 11 : int r=0;
145 : int fdlock;
146 :
147 11 : 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 118 : int lock_release(struct lock *lock)
163 : {
164 118 : int ret=0;
165 118 : if(!lock || lock->status!=GET_LOCK_GOT) return 0;
166 99 : if(lock->path) unlink(lock->path);
167 99 : if(lock->fd>=0)
168 : {
169 99 : if((ret=close(lock->fd)))
170 0 : logp("Could not close %s: %s\n",
171 0 : lock->path, strerror(errno));
172 99 : lock->fd=-1;
173 : }
174 99 : lock->status=GET_LOCK_NOT_GOT;
175 99 : 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 : }
|