libassa 3.5.1
Loading...
Searching...
No Matches
PidFileLock.cpp
Go to the documentation of this file.
1// -*- c++ -*-
2//------------------------------------------------------------------------------
3// PidFileLock.cpp
4//------------------------------------------------------------------------------
5// Copyright (c) 2001,2005 by Vladislav Grinchenko
6//
7// This library is free software; you can redistribute it and/or
8// modify it under the terms of the GNU Library General Public
9// License as published by the Free Software Foundation; either
10// version 2 of the License, or (at your option) any later version.
11//------------------------------------------------------------------------------
12
13//System Includes
14#include <errno.h> // errno
15#include <string.h> // strerror(3)
16#include <unistd.h>
17#include <fcntl.h>
18#include <sstream>
19#include <stdio.h>
20
21//Local Includes
22#include "assa/CommonUtils.h"
23#include "assa/PidFileLock.h"
24
25using namespace ASSA;
26
27//------------------------------------------------------------------------------
28// External Events
29//------------------------------------------------------------------------------
30
32PidFileLock () :
33 m_fd (-1),
34 m_error (0),
35 m_error_msg ("no errors")
36{
37 trace_with_mask ("PidFileLock::PidFileLock", PIDFLOCK);
38
40 l_start = l_len = l_pid = 0;
41}
42
45{
46 trace_with_mask ("PidFileLock::~PidFileLock", PIDFLOCK);
47
48 if (m_fd != -1) {
49 if (unlock_region () == 0) { // if we had a lock
50 DL((PIDFLOCK,"PID file unlocked.\n"));
51
52 unlink (m_filename.c_str ());
53 DL((PIDFLOCK,"PID file removed.\n"));
54 }
55 close (m_fd);
56 DL((PIDFLOCK,"PID lock file closed.\n"));
57 }
58}
59
60bool
62lock (const string& fname_)
63{
64 trace_with_mask ("PidFileLock::lock", PIDFLOCK);
65
66#if defined(WIN32)
67 return true;
68#else
69 int val;
70 int len;
71 m_filename = Utils::strenv (fname_.c_str ());
72 val = len = 0;
73
74 DL((PIDFLOCK,"PID lock file: \"%s\"\n", m_filename.c_str ()));
75
76 if (open_pid_file (m_filename) < 0) {
77 goto done;
78 }
79 DL((PIDFLOCK,"PID lock file opened and locked (fd=%d).\n", m_fd));
80
83 if (ftruncate (m_fd, 0) < 0) {
84 log_error("ftruncate() error");
85 goto done;
86 }
87 DL((PIDFLOCK,"PID lock file truncated.\n"));
88
91 if (write_pid () < 0) {
92 log_error("write(PID) error");
93 goto done;
94 }
95
98 if ((val = ::fcntl(m_fd, F_GETFD, 0)) < 0) {
99 log_error("fcntl(F_GETFD) error");
100 goto done;
101 }
102 val |= FD_CLOEXEC;
103
104 if (::fcntl (m_fd, F_SETFD, val) < 0) {
105 log_error("fcntl(F_SETFD) error");
106 goto done;
107 }
108 DL((PIDFLOCK,"CLOSE-ON-EXEC is set on FD.\n"));
109
110 done:
111 if (get_error () != 0) {
112 ::close (m_fd);
113 m_fd = -1;
114 }
115 return m_error == 0 ? true : false;
116
117#endif // !def WIN32
118}
119
120
130int
132write_pid ()
133{
134 trace_with_mask ("PidFileLock::write_pid", PIDFLOCK);
135
136#if defined (WIN32)
137 return 0;
138#else
139 std::ostringstream mypid;
140 size_t len;
141
142 this->l_pid = getpid ();
143 mypid << this->l_pid << std::ends;
144 len = strlen (mypid.str ().c_str ());
145
146#ifdef __CYGWIN__
147
148 unlock_region (); // remove shared (weak) lock
150
151 if (write (m_fd, mypid.str ().c_str (), len) != len) {
152 return -1;
153 }
154 DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", l_pid));
155 unlock_region (); // give up the exclusive lock
156 lock_region (); // place shared (weak) lock
157
158#else // POSIX-compliant locks
159
160 if (write (m_fd, mypid.str ().c_str (), len) != len) {
161 return -1;
162 }
163 DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", this->l_pid));
164
165#endif
166 return 0;
167
168#endif // !def WIN32
169}
170
171
172//------------------------------------------------------------------------------
173// Utility functions
174//------------------------------------------------------------------------------
175
176int
179{
180 trace_with_mask ("PidFileLock::lock_region", PIDFLOCK);
181 int ret;
182
183#if defined (WIN32)
184 return 0;
185#else
186
187#ifdef __CYGWIN__
188 this->l_type = F_RDLCK; // shared lock
189#else
190 this->l_type = F_WRLCK;
191#endif
192
193 this->l_start = 0;
194 this->l_whence = SEEK_SET;
195 this->l_len = 0;
196
197 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
198
199 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, %s) returned: %d\n",
200 m_fd,
201 (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"),
202 ret));
203
204 return (ret);
205
206#endif // !def WIN32
207}
208
209
210int
213{
214 trace_with_mask ("PidFileLock::lock_region_exclusive", PIDFLOCK);
215 int ret = 0;
216
217#if defined (WIN32)
218 return 0;
219#else
220
221#ifdef __CYGWIN__
222 this->l_type = F_WRLCK; // exclusive lock - read would fail
223 this->l_start = 0;
224 this->l_whence = SEEK_SET;
225 this->l_len = 0;
226
227 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
228
229 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_WRLCK) returned: %d\n", m_fd, ret));
230#endif
231
232 return (ret);
233
234#endif // !def WIN32
235}
236
237int
240{
241 trace_with_mask ("PidFileLock::unlock_region", PIDFLOCK);
242 int ret;
243
244#if defined (WIN32)
245 return 0;
246#else
247
248 this->l_type = F_UNLCK;
249 this->l_start = 0;
250 this->l_whence = SEEK_SET;
251 this->l_len = 0;
252
253 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
254
255 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_UNLCK) returned: %d\n",
256 m_fd, ret));
257
258 return (ret);
259
260#endif // !def WIN32
261}
262
263
292int
295{
296 trace_with_mask ("PidFileLock::get_lock_status", PIDFLOCK);
297 int ret;
298
299#if defined (WIN32)
300 return 0;
301#else
302
303#ifndef __CYGWIN__ // POSIX-compliant locking
304
305 this->l_type = F_WRLCK;
306 this->l_start = 0;
307 this->l_whence = SEEK_SET;
308 this->l_len = 0;
309
310 ret = ::fcntl (m_fd, F_GETLK, static_cast<struct flock*>(this));
311
312 DL((PIDFLOCK,"fcntl(fd=%d, F_GETLK, %s) returned: %d\n",
313 m_fd,
314 (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"),
315 ret));
316 if (ret < 0) {
317 EL ((PIDFLOCK,"fcntl() failed. l_pid = %d\n", this->l_pid));
318 }
319 return (ret);
320
321#else // CYGWIN
322
323 if (lock_region_exclusive () < 0) { // why exclusive?
324 if (unlock_region () < 0) { // already locked
325 char buf[64];
326 pid_t pid; // someone else got it
327 this->l_type = F_RDLCK;
328 if (read (m_fd, buf, 64) > 0) {
329 if (sscanf (buf, "%d", &pid) == 1) {
330 this->l_pid = pid;
331 }
332 }
333 else {
334 this->l_pid = 1; // no real PID information
335 }
336 }
337 }
338 else {
339 unlock_region (); // return the lock into its prestine state
340 }
341 return (0);
342
343#endif // !def CYGWIN
344
345#endif // !def WIN32
346
347}
348
353pid_t
356{
357 trace_with_mask ("PidFileLock::test_region", PIDFLOCK);
358 int ret;
359
360#if defined (WIN32)
361 return 0;
362#else
363
364 ret = get_lock_status ();
365
366 if (ret < 0) {
367 DL((PIDFLOCK,"Failed to retrieve lock status.\n"));
368 return 1;
369 }
370 if (this->l_type == F_UNLCK) {
371 DL((PIDFLOCK,"Region is not locked.\n"));
372 return(0);
373 }
374
375 DL((PIDFLOCK,"Region is already locked by PID %d\n", this->l_pid));
376 return (this->l_pid);
377
378#endif // !def WIN32
379}
380
381
382void
384dump (void)
385{
386 trace_with_mask("PidFileLock::dump", PIDFLOCK);
387
388#if !defined (WIN32)
389
390 DL((PIDFLOCK,"m_filename : \"%s\"\n", m_filename.c_str()));
391 DL((PIDFLOCK,"m_error : %d\n", get_error ()));
392 DL((PIDFLOCK,"m_error_msg: \"%s\"\n", get_error_msg ()));
393 DL((PIDFLOCK,"m_fd : %d\n", m_fd));
394
395 if (m_fd == -1) return;
396
397 test_region ();
398
399 if (this->l_type == F_RDLCK)
400 DL((PIDFLOCK,"l_type : F_RDLCK"));
401
402 if (this->l_type == F_WRLCK)
403 DL((PIDFLOCK,"l_type : F_WRLCK"));
404
405 if (this->l_type == F_UNLCK)
406 DL((PIDFLOCK,"l_type : F_UNLCK"));
407
408 DL((PIDFLOCK,"l_whence : %s\n",
409 this->l_whence == SEEK_SET ? "SEEK_SET" :
410 this->l_whence == SEEK_CUR ? "SEEK_CUR" : "SEEK_END"));
411
412 DL((PIDFLOCK,"l_start : %d\n", this->l_start));
413 DL((PIDFLOCK,"l_len : %d\n", this->l_len ));
414 DL((PIDFLOCK,"l_pid : %ld\n", this->l_pid ));
415
416#endif // !def WIN32
417}
418
419void
421log_error (const char* msg_)
422{
423 m_error = errno;
424 EL((ASSAERR,
425 "Error: \"Failed to get a lock on PID file - %s\".\n", msg_));
426}
427
428
433pid_t
435open_pid_file (const std::string& fname_)
436{
437 trace_with_mask("PidFileLock::open_pid_file", PIDFLOCK);
438
439#if !defined (WIN32)
440
441 m_fd = ::open (fname_.c_str (), O_WRONLY|O_CREAT, 0644);
442 if (m_fd < 0) {
443 log_error("open() error.");
444 return -1;
445 }
446
452 if ((owner_pid = test_region ()) > 0) {
453 log_error ("PID file is already locked (by someone).");
454 m_error = EPERM;
455 return -1;
456 }
457
460 if (lock_region () < 0) {
461 if (errno == EACCES || errno == EAGAIN) {
462 log_error("PID file is locked by another process");
463 }
464 else {
465 log_error("write lock error");
466 }
467 return -1;
468 }
469
470#endif // !def WIN32
471
472 return 0;
473}
474
#define EL(X)
A macro for writing error message to the Logger.
Definition Logger.h:285
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition Logger.h:437
A utility class for creating and managing process PID lock file.
A wrapper class to provide AutoPtr with reference semantics.
Definition AutoPtr.h:32
int get_lock_status()
Retrieve lock status.
~PidFileLock()
Destructor.
int write_pid()
Write our process pid to the lock file.
pid_t open_pid_file(const std::string &fname_)
Open pid file in a cross-platform way.
int m_error
Last system call error.
const char * get_error_msg() const
In case of error, return a verbal description of the last error.
PidFileLock()
Constructor.
int get_error() const
Return last errno value.
void log_error(const char *msg_)
Log an error message to the log file and set internal error to errno.
pid_t test_region()
Test if file is unlocked.
string m_filename
Lock file name.
int m_fd
Lock file descriptor.
void dump()
Write the state of the lock to debug file.
bool lock(const string &filename_)
Lock the file.
int lock_region()
Lock the entire file.
int lock_region_exclusive()
Lock the entire file (only under Cygwin).
int unlock_region()
Unlock the entire file.
std::string strenv(const char *in_)
Expand the passed string in_ by substituting environment variable names for their values.
@ ASSAERR
ASSA and system errors
Definition LogMask.h:34
@ PIDFLOCK
Class PidFileLock messages
Definition LogMask.h:35