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