00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <errno.h>
00015 #include <string.h>
00016 #include <unistd.h>
00017 #include <fcntl.h>
00018 #include <sstream>
00019 #include <stdio.h>
00020
00021
00022 #include "assa/CommonUtils.h"
00023 #include "assa/PidFileLock.h"
00024
00025 using namespace ASSA;
00026
00027
00028
00029
00030
00031 PidFileLock::
00032 PidFileLock () :
00033 m_fd (-1),
00034 m_error (0),
00035 m_error_msg ("no errors")
00036 {
00037 trace_with_mask ("PidFileLock::PidFileLock", PIDFLOCK);
00038
00039 l_whence = SEEK_SET;
00040 l_start = l_len = l_pid = 0;
00041 }
00042
00043 PidFileLock::
00044 ~PidFileLock ()
00045 {
00046 trace_with_mask ("PidFileLock::~PidFileLock", PIDFLOCK);
00047
00048 if (m_fd != -1) {
00049 if (unlock_region () == 0) {
00050 DL((PIDFLOCK,"PID file unlocked.\n"));
00051
00052 unlink (m_filename.c_str ());
00053 DL((PIDFLOCK,"PID file removed.\n"));
00054 }
00055 close (m_fd);
00056 DL((PIDFLOCK,"PID lock file closed.\n"));
00057 }
00058 }
00059
00060 bool
00061 PidFileLock::
00062 lock (const string& fname_)
00063 {
00064 trace_with_mask ("PidFileLock::lock", PIDFLOCK);
00065
00066 #if defined(WIN32)
00067 return true;
00068 #else
00069 int val;
00070 int len;
00071 m_filename = Utils::strenv (fname_.c_str ());
00072 val = len = 0;
00073
00074 DL((PIDFLOCK,"PID lock file: \"%s\"\n", m_filename.c_str ()));
00075
00076 if (open_pid_file (m_filename) < 0) {
00077 goto done;
00078 }
00079 DL((PIDFLOCK,"PID lock file opened and locked (fd=%d).\n", m_fd));
00080
00083 if (ftruncate (m_fd, 0) < 0) {
00084 log_error("ftruncate() error");
00085 goto done;
00086 }
00087 DL((PIDFLOCK,"PID lock file truncated.\n"));
00088
00091 if (write_pid () < 0) {
00092 log_error("write(PID) error");
00093 goto done;
00094 }
00095
00098 if ((val = ::fcntl(m_fd, F_GETFD, 0)) < 0) {
00099 log_error("fcntl(F_GETFD) error");
00100 goto done;
00101 }
00102 val |= FD_CLOEXEC;
00103
00104 if (::fcntl (m_fd, F_SETFD, val) < 0) {
00105 log_error("fcntl(F_SETFD) error");
00106 goto done;
00107 }
00108 DL((PIDFLOCK,"CLOSE-ON-EXEC is set on FD.\n"));
00109
00110 done:
00111 if (get_error () != 0) {
00112 ::close (m_fd);
00113 m_fd = -1;
00114 }
00115 return m_error == 0 ? true : false;
00116
00117 #endif // !def WIN32
00118 }
00119
00120
00130 int
00131 PidFileLock::
00132 write_pid ()
00133 {
00134 trace_with_mask ("PidFileLock::write_pid", PIDFLOCK);
00135
00136 #if defined (WIN32)
00137 return 0;
00138 #else
00139 std::ostringstream mypid;
00140 size_t len;
00141
00142 this->l_pid = getpid ();
00143 mypid << this->l_pid << std::ends;
00144 len = strlen (mypid.str ().c_str ());
00145
00146 #ifdef __CYGWIN__
00147
00148 unlock_region ();
00149 lock_region_exclusive ();
00150
00151 if (write (m_fd, mypid.str ().c_str (), len) != len) {
00152 return -1;
00153 }
00154 DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", l_pid));
00155 unlock_region ();
00156 lock_region ();
00157
00158 #else // POSIX-compliant locks
00159
00160 if (write (m_fd, mypid.str ().c_str (), len) != len) {
00161 return -1;
00162 }
00163 DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", this->l_pid));
00164
00165 #endif
00166 return 0;
00167
00168 #endif // !def WIN32
00169 }
00170
00171
00172
00173
00174
00175
00176 int
00177 PidFileLock::
00178 lock_region ()
00179 {
00180 trace_with_mask ("PidFileLock::lock_region", PIDFLOCK);
00181 int ret;
00182
00183 #if defined (WIN32)
00184 return 0;
00185 #else
00186
00187 #ifdef __CYGWIN__
00188 this->l_type = F_RDLCK;
00189 #else
00190 this->l_type = F_WRLCK;
00191 #endif
00192
00193 this->l_start = 0;
00194 this->l_whence = SEEK_SET;
00195 this->l_len = 0;
00196
00197 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
00198
00199 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, %s) returned: %d\n",
00200 m_fd,
00201 (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"),
00202 ret));
00203
00204 return (ret);
00205
00206 #endif // !def WIN32
00207 }
00208
00209
00210 int
00211 PidFileLock::
00212 lock_region_exclusive ()
00213 {
00214 trace_with_mask ("PidFileLock::lock_region_exclusive", PIDFLOCK);
00215 int ret = 0;
00216
00217 #if defined (WIN32)
00218 return 0;
00219 #else
00220
00221 #ifdef __CYGWIN__
00222 this->l_type = F_WRLCK;
00223 this->l_start = 0;
00224 this->l_whence = SEEK_SET;
00225 this->l_len = 0;
00226
00227 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
00228
00229 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_WRLCK) returned: %d\n", m_fd, ret));
00230 #endif
00231
00232 return (ret);
00233
00234 #endif // !def WIN32
00235 }
00236
00237 int
00238 PidFileLock::
00239 unlock_region ()
00240 {
00241 trace_with_mask ("PidFileLock::unlock_region", PIDFLOCK);
00242 int ret;
00243
00244 #if defined (WIN32)
00245 return 0;
00246 #else
00247
00248 this->l_type = F_UNLCK;
00249 this->l_start = 0;
00250 this->l_whence = SEEK_SET;
00251 this->l_len = 0;
00252
00253 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
00254
00255 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_UNLCK) returned: %d\n",
00256 m_fd, ret));
00257
00258 return (ret);
00259
00260 #endif // !def WIN32
00261 }
00262
00263
00292 int
00293 PidFileLock::
00294 get_lock_status ()
00295 {
00296 trace_with_mask ("PidFileLock::get_lock_status", PIDFLOCK);
00297 int ret;
00298
00299 #if defined (WIN32)
00300 return 0;
00301 #else
00302
00303 #ifndef __CYGWIN__ // POSIX-compliant locking
00304
00305 this->l_type = F_WRLCK;
00306 this->l_start = 0;
00307 this->l_whence = SEEK_SET;
00308 this->l_len = 0;
00309
00310 ret = ::fcntl (m_fd, F_GETLK, static_cast<struct flock*>(this));
00311
00312 DL((PIDFLOCK,"fcntl(fd=%d, F_GETLK, %s) returned: %d\n",
00313 m_fd,
00314 (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"),
00315 ret));
00316 if (ret < 0) {
00317 EL ((PIDFLOCK,"fcntl() failed. l_pid = %d\n", this->l_pid));
00318 }
00319 return (ret);
00320
00321 #else // CYGWIN
00322
00323 if (lock_region_exclusive () < 0) {
00324 if (unlock_region () < 0) {
00325 char buf[64];
00326 pid_t pid;
00327 this->l_type = F_RDLCK;
00328 if (read (m_fd, buf, 64) > 0) {
00329 if (sscanf (buf, "%d", &pid) == 1) {
00330 this->l_pid = pid;
00331 }
00332 }
00333 else {
00334 this->l_pid = 1;
00335 }
00336 }
00337 }
00338 else {
00339 unlock_region ();
00340 }
00341 return (0);
00342
00343 #endif // !def CYGWIN
00344
00345 #endif // !def WIN32
00346
00347 }
00348
00353 pid_t
00354 PidFileLock::
00355 test_region ()
00356 {
00357 trace_with_mask ("PidFileLock::test_region", PIDFLOCK);
00358 int ret;
00359
00360 #if defined (WIN32)
00361 return 0;
00362 #else
00363
00364 ret = get_lock_status ();
00365
00366 if (ret < 0) {
00367 DL((PIDFLOCK,"Failed to retrieve lock status.\n"));
00368 return 1;
00369 }
00370 if (this->l_type == F_UNLCK) {
00371 DL((PIDFLOCK,"Region is not locked.\n"));
00372 return(0);
00373 }
00374
00375 DL((PIDFLOCK,"Region is already locked by PID %d\n", this->l_pid));
00376 return (this->l_pid);
00377
00378 #endif // !def WIN32
00379 }
00380
00381
00382 void
00383 PidFileLock::
00384 dump (void)
00385 {
00386 trace_with_mask("PidFileLock::dump", PIDFLOCK);
00387
00388 #if !defined (WIN32)
00389
00390 DL((PIDFLOCK,"m_filename : \"%s\"\n", m_filename.c_str()));
00391 DL((PIDFLOCK,"m_error : %d\n", get_error ()));
00392 DL((PIDFLOCK,"m_error_msg: \"%s\"\n", get_error_msg ()));
00393 DL((PIDFLOCK,"m_fd : %d\n", m_fd));
00394
00395 if (m_fd == -1) return;
00396
00397 test_region ();
00398
00399 if (this->l_type == F_RDLCK)
00400 DL((PIDFLOCK,"l_type : F_RDLCK"));
00401
00402 if (this->l_type == F_WRLCK)
00403 DL((PIDFLOCK,"l_type : F_WRLCK"));
00404
00405 if (this->l_type == F_UNLCK)
00406 DL((PIDFLOCK,"l_type : F_UNLCK"));
00407
00408 DL((PIDFLOCK,"l_whence : %s\n",
00409 this->l_whence == SEEK_SET ? "SEEK_SET" :
00410 this->l_whence == SEEK_CUR ? "SEEK_CUR" : "SEEK_END"));
00411
00412 DL((PIDFLOCK,"l_start : %d\n", this->l_start));
00413 DL((PIDFLOCK,"l_len : %d\n", this->l_len ));
00414 DL((PIDFLOCK,"l_pid : %ld\n", this->l_pid ));
00415
00416 #endif // !def WIN32
00417 }
00418
00419 void
00420 PidFileLock::
00421 log_error (const char* msg_)
00422 {
00423 m_error = errno;
00424 EL((ASSAERR,
00425 "Error: \"Failed to get a lock on PID file - %s\".\n", msg_));
00426 }
00427
00428
00433 pid_t
00434 PidFileLock::
00435 open_pid_file (const std::string& fname_)
00436 {
00437 trace_with_mask("PidFileLock::open_pid_file", PIDFLOCK);
00438
00439 #if !defined (WIN32)
00440
00441 m_fd = ::open (fname_.c_str (), O_WRONLY|O_CREAT, 0644);
00442 if (m_fd < 0) {
00443 log_error("open() error.");
00444 return -1;
00445 }
00446
00451 pid_t owner_pid;
00452 if ((owner_pid = test_region ()) > 0) {
00453 log_error ("PID file is already locked (by someone).");
00454 m_error = EPERM;
00455 return -1;
00456 }
00457
00460 if (lock_region () < 0) {
00461 if (errno == EACCES || errno == EAGAIN) {
00462 log_error("PID file is locked by another process");
00463 }
00464 else {
00465 log_error("write lock error");
00466 }
00467 return -1;
00468 }
00469
00470 #endif // !def WIN32
00471
00472 return 0;
00473 }
00474