blob: 14dc85d398b5824b023b2f4112ae4cb144793416 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <cc++/config.h>
40#include <cc++/export.h>
41#include <cc++/thread.h>
42#include <cc++/process.h>
43#include <cc++/strchar.h>
44
45#include <sys/stat.h>
46#include <cstdlib>
47#include <cstdio>
48#include <cerrno>
49
50#ifdef CCXX_NAMESPACES
51namespace ost {
52#endif
53
54#ifdef WIN32
55
56Lockfile::Lockfile()
57{
58 _mutex = INVALID_HANDLE_VALUE;
59 _flagged = false;
60}
61
62Lockfile::Lockfile(const char *name)
63{
64 _mutex = INVALID_HANDLE_VALUE;
65 _flagged = false;
66 lock(name);
67}
68
69bool Lockfile::lock(const char *name)
70{
71 char mname[65];
72 char *ext = strrchr((char *)name, '/');
73
74 if(ext)
75 name = ++ext;
76
77 unlock();
78 snprintf(mname, sizeof(mname) - 4, "_lock_%s", name);
79 ext = strrchr(mname, '.');
80 if(ext && !stricmp(ext, ".lock")) {
81 *ext = 0;
82 ext = NULL;
83 }
84 if(!ext)
85 addString(mname, sizeof(mname), ".lck");
86 _mutex = CreateMutex(NULL, FALSE, mname);
87 if(WaitForSingleObject(_mutex, 200) == WAIT_OBJECT_0)
88 _flagged = true;
89 return _flagged;
90}
91
92void Lockfile::unlock(void)
93{
94 if(_mutex == INVALID_HANDLE_VALUE)
95 return;
96
97 if(_flagged)
98 ReleaseMutex(_mutex);
99 CloseHandle(_mutex);
100 _flagged = false;
101 _mutex = INVALID_HANDLE_VALUE;
102}
103
104bool Lockfile::isLocked(void)
105{
106 return _flagged;
107}
108
109#else
110
111Lockfile::Lockfile()
112{
113 _path = NULL;
114}
115
116Lockfile::Lockfile(const char *name)
117{
118 _path = NULL;
119 lock(name);
120}
121
122bool Lockfile::lock(const char *name)
123{
124 struct stat ino;
125 int fd, pid, status;
126 const char *ext;
127 char buffer[128];
128 bool rtn = true;
129
130 unlock();
131
132 ext = strrchr(name, '/');
133 if(ext)
134 ext = strrchr(ext, '.');
135 else
136 ext = strrchr(name, '.');
137
138 if(strchr(name, '/')) {
139 _path = new char[strlen(name) + 1];
140 strcpy(_path, name);
141 }
142 else if(ext && !stricmp(ext, ".pid")) {
143 if(stat("/var/run", &ino))
144 snprintf(buffer, sizeof(buffer), "/tmp/.%s", name);
145 else
146 snprintf(buffer, sizeof(buffer), "/var/run/%s", name);
147 _path = new char[strlen(buffer) + 1];
148 strcpy(_path, buffer);
149 }
150 else {
151 if(!ext)
152 ext = ".lock";
153 if(stat("/var/lock", &ino))
154 snprintf(buffer, sizeof(buffer), "/tmp/.%s%s", name, ext);
155 else
156 snprintf(buffer, sizeof(buffer), "/var/lock/%s%s", name, ext);
157
158 _path = new char[strlen(buffer) + 1];
159 strcpy(_path, buffer);
160 }
161
162 for(;;) {
163 fd = ::open(_path, O_WRONLY | O_CREAT | O_EXCL, 0660);
164 if(fd > 0) {
165 pid = getpid();
166 snprintf(buffer, sizeof(buffer), "%d\n", pid);
167 if(::write(fd, buffer, strlen(buffer)))
168 rtn = false;
169 ::close(fd);
170 return rtn;
171 }
172 if(fd < 0 && errno != EEXIST) {
173 delete[] _path;
174 return false;
175 }
176
177 fd = ::open(_path, O_RDONLY);
178 if(fd < 0) {
179 if(errno == ENOENT)
180 continue;
181 delete[] _path;
182 return false;
183 }
184
185 Thread::sleep(2000);
186 status = ::read(fd, buffer, sizeof(buffer) - 1);
187 if(status < 1) {
188 ::close(fd);
189 continue;
190 }
191
192 buffer[status] = 0;
193 pid = atoi(buffer);
194 if(pid) {
195 if(pid == getpid()) {
196 status = -1;
197 errno = 0;
198 }
199 else
200 status = kill(pid, 0);
201
202 if(!status || (errno == EPERM)) {
203 ::close(fd);
204 delete[] _path;
205 return false;
206 }
207 }
208 ::close(fd);
209 ::unlink(_path);
210 }
211}
212
213void Lockfile::unlock(void)
214{
215 if(_path) {
216 remove(_path);
217 delete[] _path;
218 _path = NULL;
219 }
220}
221
222bool Lockfile::isLocked(void)
223{
224 if(_path)
225 return true;
226
227 return false;
228}
229
230#endif
231
232#ifdef CCXX_NAMESPACES
233}
234#endif
235
236/** EMACS **
237 * Local variables:
238 * mode: c++
239 * c-basic-offset: 4
240 * End:
241 */